diff --git a/.circleci/config.yml b/.circleci/config.yml
index f102a5659..054a60a28 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -9,20 +9,20 @@ version: 2.1
parameters:
ubuntu-2004-docker-image:
type: string
- # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-5
- default: "solbuildpackpusher/solidity-buildpack-deps@sha256:2d306b8da3485c2584a8868d656dc36c1ae50f003ff085ad2e904e312534b9b7"
+ # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-6
+ default: "solbuildpackpusher/solidity-buildpack-deps@sha256:da44d7f78e093f7f0415abf07f7c1fd1c2ed4fa65fefea428821a05186c42ec9"
ubuntu-2004-clang-docker-image:
type: string
- # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-5
- default: "solbuildpackpusher/solidity-buildpack-deps@sha256:4fbc7a99dd0b204fef587856d89640e4b2060d459ba15c32b89733b2a6054d7f"
+ # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-6
+ default: "solbuildpackpusher/solidity-buildpack-deps@sha256:c78dd9c48d393b57afe053aeb2d0d358a9f31ac85039a181724c2f8408d0bcf8"
ubuntu-1604-clang-ossfuzz-docker-image:
type: string
- # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-8
- default: "solbuildpackpusher/solidity-buildpack-deps@sha256:42f47b7ddafbf57b4e48357022cf34dc38ae477b05ddc2210e7ed68d821c2019"
+ # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-9
+ default: "solbuildpackpusher/solidity-buildpack-deps@sha256:5078e1d74ab6f4329e9218c2d8c0ebe2d42817a3d4c3c62ce887100cbe9bc739"
emscripten-docker-image:
type: string
- # solbuildpackpusher/solidity-buildpack-deps:emscripten-4
- default: "solbuildpackpusher/solidity-buildpack-deps@sha256:434719d8104cab47712dd1f56f255994d04eb65b802c0d382790071c1a0c074b"
+ # solbuildpackpusher/solidity-buildpack-deps:emscripten-5
+ default: "solbuildpackpusher/solidity-buildpack-deps@sha256:d28afb9624c2352ea40f157d1a321ffac77f54a21e33a8e8744f9126b780ded4"
orbs:
win: circleci/windows@2.2.0
@@ -354,8 +354,8 @@ jobs:
command: apt -q update && apt install -y python3-pip
- run:
name: Install pylint
- command: python3 -m pip install pylint z3-solver pygments-lexer-solidity
- # also z3-solver to make sure pylint knows about this module, pygments-lexer-solidity for docs
+ command: python3 -m pip install pylint z3-solver pygments-lexer-solidity parsec tabulate
+ # also z3-solver, parsec and tabulate to make sure pylint knows about this module, pygments-lexer-solidity for docs
- run:
name: Linting Python Scripts
command: ./scripts/pylint_all.py
@@ -571,7 +571,9 @@ jobs:
b_archlinux:
docker:
- - image: archlinux/base
+ # FIXME: Newer releases won't work until CircleCI updates its host machines.
+ # See https://github.com/ethereum/solidity/pull/11332
+ - image: archlinux:base-20210131.0.14634
environment:
TERM: xterm
MAKEFLAGS: -j 3
@@ -710,11 +712,19 @@ jobs:
t_archlinux_soltest: &t_archlinux_soltest
docker:
- - image: archlinux/base
+ # FIXME: Newer releases won't work until CircleCI updates its host machines.
+ # See https://github.com/ethereum/solidity/pull/11332
+ - image: archlinux:base-20210131.0.14634
environment:
EVM: constantinople
OPTIMIZE: 0
TERM: xterm
+ # For Archlinux we do not have prebuilt docker images and we would need to build evmone from source,
+ # thus we forgo semantics tests to speed things up.
+ # FIXME: Z3 4.8.11 prerelease is now in main Arch Linux repos but it makes some of our SMT
+ # tests hang. Disabling SMT tests until we get a proper release.
+ # See https://github.com/Z3Prover/z3/issues/5330 for more details.
+ SOLTEST_FLAGS: --no-semantic-tests --no-smt
steps:
- run:
name: Install runtime dependencies
diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh
index 2845b224a..f1dd4f11b 100755
--- a/.circleci/osx_install_dependencies.sh
+++ b/.circleci/osx_install_dependencies.sh
@@ -37,6 +37,8 @@ set -eu
if [ ! -f /usr/local/lib/libz3.a ] # if this file does not exists (cache was not restored), rebuild dependencies
then
+ git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
+ git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow
brew update
brew unlink python
brew install boost
@@ -55,12 +57,12 @@ then
rm -rf z3-4.8.10-x64-osx-10.15.7
# evmone
- wget https://github.com/ethereum/evmone/releases/download/v0.4.0/evmone-0.4.0-darwin-x86_64.tar.gz
- tar xzpf evmone-0.4.0-darwin-x86_64.tar.gz -C /usr/local
- rm -f evmone-0.4.0-darwin-x86_64.tar.gz
+ wget https://github.com/ethereum/evmone/releases/download/v0.7.0/evmone-0.7.0-darwin-x86_64.tar.gz
+ tar xzpf evmone-0.7.0-darwin-x86_64.tar.gz -C /usr/local
+ rm -f evmone-0.7.0-darwin-x86_64.tar.gz
# hera
- wget https://github.com/ewasm/hera/releases/download/v0.3.2/hera-0.3.2-darwin-x86_64.tar.gz
- tar xzpf hera-0.3.2-darwin-x86_64.tar.gz -C /usr/local
- rm -f hera-0.3.2-darwin-x86_64.tar.gz
+ wget https://github.com/ewasm/hera/releases/download/v0.3.2-evmc8/hera-0.3.2+commit.dc886eb7-darwin-x86_64.tar.gz
+ tar xzpf hera-0.3.2+commit.dc886eb7-darwin-x86_64.tar.gz -C /usr/local
+ rm -f hera-0.3.2+commit.dc886eb7-darwin-x86_64.tar.gz
fi
diff --git a/.circleci/soltest_all.sh b/.circleci/soltest_all.sh
index c407ea627..a79228637 100755
--- a/.circleci/soltest_all.sh
+++ b/.circleci/soltest_all.sh
@@ -28,7 +28,9 @@ set -e
REPODIR="$(realpath "$(dirname "$0")"/..)"
-EVM_VALUES=(homestead byzantium constantinople petersburg istanbul)
+EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin)
+DEFAULT_EVM=berlin
+[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
OPTIMIZE_VALUES=(0 1)
STEPS=$(( 1 + ${#EVM_VALUES[@]} * ${#OPTIMIZE_VALUES[@]} ))
@@ -45,7 +47,7 @@ STEP=1
# Run for ABI encoder v1, without SMTChecker tests.
-[[ " $RUN_STEPS " == *" $STEP "* ]] && EVM=istanbul OPTIMIZE=1 ABI_ENCODER_V1=1 BOOST_TEST_ARGS="-t !smtCheckerTests" "${REPODIR}/.circleci/soltest.sh"
+[[ " $RUN_STEPS " == *" $STEP "* ]] && EVM="${DEFAULT_EVM}" OPTIMIZE=1 ABI_ENCODER_V1=1 BOOST_TEST_ARGS="-t !smtCheckerTests" "${REPODIR}/.circleci/soltest.sh"
STEP=$((STEP + 1))
for OPTIMIZE in "${OPTIMIZE_VALUES[@]}"
@@ -56,7 +58,7 @@ do
EWASM_ARGS=""
[ "${EVM}" = "byzantium" ] && [ "${OPTIMIZE}" = "0" ] && EWASM_ARGS="--ewasm"
ENFORCE_GAS_ARGS=""
- [ "${EVM}" = "istanbul" ] && ENFORCE_GAS_ARGS="--enforce-gas-cost"
+ [ "${EVM}" = "${DEFAULT_EVM}" ] && ENFORCE_GAS_ARGS="--enforce-gas-cost"
# Run SMTChecker tests only when OPTIMIZE == 0
DISABLE_SMTCHECKER=""
[ "${OPTIMIZE}" != "0" ] && DISABLE_SMTCHECKER="-t !smtCheckerTests"
diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.md b/.github/ISSUE_TEMPLATE/documentation_issue.md
new file mode 100644
index 000000000..c0706b5f3
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/documentation_issue.md
@@ -0,0 +1,22 @@
+---
+name: Documentation Issue
+about: Solidity documentation.
+---
+
+## Page
+
+
+
+## Abstract
+
+
+
+## Pull request
+
+
diff --git a/.gitignore b/.gitignore
index 0238cc349..9322b0c81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ prerelease.txt
/build*
emscripten_build/
docs/_build
+docs/_static/robots.txt
__pycache__
docs/utils/*.pyc
/deps/downloads/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 002396eeb..c35426f7d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,7 +21,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
-set(PROJECT_VERSION "0.8.5")
+set(PROJECT_VERSION "0.8.7")
# OSX target needed in order to support std::visit
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
diff --git a/Changelog.md b/Changelog.md
index 541d22e9e..2f10594ea 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -3,7 +3,78 @@
Breaking changes:
* `error` is now a keyword that can only be used for defining errors.
-### 0.8.5 (unreleased)
+
+### 0.8.7 (unreleased)
+
+Language Features:
+
+
+Compiler Features:
+ * AssemblyStack: Also run opcode-based optimizer when compiling Yul code.
+ * Yul EVM Code Transform: Do not reuse stack slots that immediately become unreachable.
+ * Yul EVM Code Transform: Also pop unused argument slots for functions without return variables (under the same restrictions as for functions with return variables).
+ * Yul Optimizer: Move function arguments and return variables to memory with the experimental Stack Limit Evader (which is not enabled by default).
+
+
+Bugfixes:
+ * Code Generator: Fix crash when passing an empty string literal to ``bytes.concat()``.
+ * Code Generator: Fix internal compiler error when calling functions bound to calldata structs and arrays.
+ * Code Generator: Fix internal compiler error when passing a 32-byte hex literal or a zero literal to ``bytes.concat()`` by disallowing such literals.
+ * Type Checker: Fix internal error and prevent static calls to unimplemented modifiers.
+ * Yul Code Generator: Fix internal compiler error when using a long literal with bitwise negation.
+
+
+### 0.8.6 (2021-06-22)
+
+Language Features:
+ * Yul: Special meaning of ``".metadata"`` data object in Yul object.
+
+
+Bugfixes:
+ * Control Flow Graph: Fix incorrectly reported unreachable code.
+ * Solc-Js: When running ``solcjs`` without the ``--optimize`` flag, use ``settings.optimizer.enabled=false`` in Standard JSON instead of omitting the key.
+ * Standard JSON: Omitting ``settings.optimizer.enabled`` was not equivalent to setting it to ``false``. It meant disabling also the peephole optimizer and jumpdest remover which by default still run with ``enabled=false``.
+
+
+### 0.8.5 (2021-06-10)
+
+Language Features:
+ * Allowing conversion from ``bytes`` and ``bytes`` slices to ``bytes1``/.../``bytes32``.
+ * Yul: Add ``verbatim`` builtin function to inject arbitrary bytecode.
+
+
+Compiler Features:
+ * Code Generator: Insert helper functions for panic codes instead of inlining unconditionally. This can reduce costs if many panics (checks) are inserted, but can increase costs where few panics are used.
+ * EVM: Set the default EVM version to "Berlin".
+ * SMTChecker: Function definitions can be annotated with the custom Natspec tag ``custom:smtchecker abstract-function-nondet`` to be abstracted by a nondeterministic value when called.
+ * Standard JSON / combined JSON: New artifact "functionDebugData" that contains bytecode offsets of entry points of functions and potentially more information in the future.
+ * Yul Optimizer: Evaluate ``keccak256(a, c)``, when the value at memory location ``a`` is known at compile time and ``c`` is a constant ``<= 32``.
+
+
+Bugfixes:
+ * AST: Do not output value of Yul literal if it is not a valid UTF-8 string.
+ * Code Generator: Fix internal error when function arrays are assigned to storage variables and the function types can be implicitly converted but are not identical.
+ * Code Generator: Fix internal error when super would have to skip an unimplemented function in the virtual resolution order.
+ * Control Flow Graph: Assume unimplemented modifiers use a placeholder.
+ * Control Flow Graph: Take internal calls to functions that always revert into account for reporting unused or unassigned variables.
+ * Function Call Graph: Fix internal error connected with circular constant references.
+ * Name Resolver: Do not issue shadowing warning if the shadowing name is not directly accessible.
+ * Natspec: Allow multiple ``@return`` tags on public state variable documentation.
+ * SMTChecker: Fix internal error on conversion from ``bytes`` to ``fixed bytes``.
+ * SMTChecker: Fix internal error on external calls from the constructor.
+ * SMTChecker: Fix internal error on struct constructor with fixed bytes member initialized with string literal.
+ * Source Locations: Properly set source location of scoped blocks.
+ * Standard JSON: Properly allow the ``inliner`` setting under ``settings.optimizer.details``.
+ * Type Checker: Fix internal compiler error related to having mapping types in constructor parameter for abstract contracts.
+ * Type Checker: Fix internal compiler error when attempting to use an invalid external function type on pre-byzantium EVMs.
+ * Type Checker: Fix internal compiler error when overriding receive ether function with one having different parameters during inheritance.
+ * Type Checker: Make errors about (nested) mapping type in event or error parameter into fatal type errors.
+ * Type Checker: Fix internal compiler error when overriding an implemented modifier with an unimplemented one.
+
+
+AST Changes:
+ * Add member `hexValue` for Yul string and hex literals.
+
### 0.8.4 (2021-04-21)
diff --git a/README.md b/README.md
index 9a79a9cef..abc8616e0 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@
[](https://gitter.im/ethereum/solidity)
[](https://forum.soliditylang.org/)
[](https://twitter.com/solidity_lang)
+[](https://fosstodon.org/@solidity)
You can talk to us on Gitter and Matrix, tweet at us on Twitter or create a new topic in the Solidity forum. Questions, feedback, and suggestions are welcome!
diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md
index af3bbfdaa..7fe7c361c 100644
--- a/ReleaseChecklist.md
+++ b/ReleaseChecklist.md
@@ -61,7 +61,6 @@
### Documentation
- [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` at the bottom of the page and click `BUILD`).
- [ ] In the admin panel, select `Versions` in the menu and set the default version to the released one.
- - [ ] If it is a non-breaking release, block indexing of previous release version in the ``robots.txt`` file.
### Release solc-js
- [ ] Wait until solc-bin was properly deployed. You can test this via remix - a test run through remix is advisable anyway.
@@ -72,5 +71,7 @@
### Post-release
- [ ] Publish the blog post.
- [ ] Create a commit to increase the version number on ``develop`` in ``CMakeLists.txt`` and add a new skeleton changelog entry.
- - [ ] Announce on Twitter and Reddit.
+ - [ ] Announce on Twitter, including links to the release and the blog post.
+ - [ ] Share announcement on Reddit and Solidity forum.
+ - [ ] Update the release information section on [soliditylang.org](https://github.com/ethereum/solidity-portal).
- [ ] Lean back, wait for bug reports and repeat from step 1 :)
diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst
index 57aa8f80a..3076044d3 100644
--- a/docs/050-breaking-changes.rst
+++ b/docs/050-breaking-changes.rst
@@ -290,7 +290,7 @@ It is still possible to interface with contracts written for Solidity versions p
v0.5.0 (or the other way around) by defining interfaces for them.
Consider you have the following pre-0.5.0 contract already deployed:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.25;
@@ -308,7 +308,7 @@ Consider you have the following pre-0.5.0 contract already deployed:
This will no longer compile with Solidity v0.5.0. However, you can define a compatible interface for it:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -326,7 +326,7 @@ the function will work with ``staticcall``.
Given the interface defined above, you can now easily use the already deployed pre-0.5.0 contract:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -347,7 +347,7 @@ Similarly, pre-0.5.0 libraries can be used by defining the functions of the libr
supplying the address of the pre-0.5.0 library during linking (see :ref:`commandline-compiler` for how to use the
commandline compiler for linking):
-::
+.. code-block:: solidity
// This will not compile after 0.6.0
// SPDX-License-Identifier: GPL-3.0
@@ -372,7 +372,7 @@ v0.5.0 with some of the changes listed in this section.
Old version:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.25;
@@ -435,7 +435,7 @@ Old version:
New version:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;
diff --git a/docs/_static/robots.txt b/docs/_static/robots.txt
deleted file mode 100644
index c526f3786..000000000
--- a/docs/_static/robots.txt
+++ /dev/null
@@ -1,95 +0,0 @@
-Sitemap: http://docs.soliditylang.org/sitemap.xml
-
-# Prevent documentation for the development branches from showing up in search results.
-Disallow: /en/develop/
-Disallow: /en/breaking/
-
-# Prevent documentation for the older Solidity versions from showing up in search results.
-
-Disallow: /en/v0.1.2/
-Disallow: /en/v0.1.3/
-Disallow: /en/v0.1.4/
-Disallow: /en/v0.1.5/
-Disallow: /en/v0.1.6/
-Disallow: /en/v0.1.7/
-Disallow: /en/v0.2.0/
-Disallow: /en/v0.2.1/
-Disallow: /en/v0.2.2/
-Disallow: /en/v0.3.0/
-Disallow: /en/v0.3.1/
-Disallow: /en/v0.3.2/
-Disallow: /en/v0.3.3/
-Disallow: /en/v0.3.4/
-Disallow: /en/v0.3.5/
-Disallow: /en/v0.3.6/
-Disallow: /en/v0.4.0/
-Disallow: /en/v0.4.1/
-Disallow: /en/v0.4.2/
-Disallow: /en/v0.4.3/
-Disallow: /en/v0.4.4/
-Disallow: /en/v0.4.5/
-Disallow: /en/v0.4.6/
-Disallow: /en/v0.4.7/
-Disallow: /en/v0.4.8/
-Disallow: /en/v0.4.9/
-Disallow: /en/v0.4.10/
-Disallow: /en/v0.4.11/
-Disallow: /en/v0.4.12/
-Disallow: /en/v0.4.13/
-Disallow: /en/v0.4.14/
-Disallow: /en/v0.4.15/
-Disallow: /en/v0.4.16/
-Disallow: /en/v0.4.17/
-Disallow: /en/v0.4.18/
-Disallow: /en/v0.4.19/
-Disallow: /en/v0.4.20/
-Disallow: /en/v0.4.21/
-Disallow: /en/v0.4.22/
-Disallow: /en/v0.4.23/
-Disallow: /en/v0.4.24/
-Disallow: /en/v0.4.25/
-Disallow: /en/v0.4.26/
-Disallow: /en/v0.5.0/
-Disallow: /en/v0.5.1/
-Disallow: /en/v0.5.2/
-Disallow: /en/v0.5.3/
-Disallow: /en/v0.5.4/
-Disallow: /en/v0.5.5/
-Disallow: /en/v0.5.6/
-Disallow: /en/v0.5.7/
-Disallow: /en/v0.5.8/
-Disallow: /en/v0.5.9/
-Disallow: /en/v0.5.10/
-Disallow: /en/v0.5.11/
-Disallow: /en/v0.5.12/
-Disallow: /en/v0.5.13/
-Disallow: /en/v0.5.14/
-Disallow: /en/v0.5.15/
-Disallow: /en/v0.5.16/
-Disallow: /en/v0.5.17/
-Disallow: /en/v0.6.0/
-Disallow: /en/v0.6.1/
-Disallow: /en/v0.6.2/
-Disallow: /en/v0.6.3/
-Disallow: /en/v0.6.4/
-Disallow: /en/v0.6.5/
-Disallow: /en/v0.6.6/
-Disallow: /en/v0.6.7/
-Disallow: /en/v0.6.8/
-Disallow: /en/v0.6.9/
-Disallow: /en/v0.6.10/
-Disallow: /en/v0.6.11/
-Disallow: /en/v0.6.12/
-Disallow: /en/v0.7.0/
-Disallow: /en/v0.7.1/
-Disallow: /en/v0.7.2/
-Disallow: /en/v0.7.3/
-Disallow: /en/v0.7.4/
-Disallow: /en/v0.7.5/
-# Allow the last patch release of the 0.7.x series
-#Disallow: /en/v0.7.6/
-Disallow: /en/v0.8.0/
-Disallow: /en/v0.8.1/
-Disallow: /en/v0.8.2/
-# Allow the latest release
-#Disallow: /en/v0.8.3/
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html
index 1db4ef92c..5f81b2320 100644
--- a/docs/_templates/layout.html
+++ b/docs/_templates/layout.html
@@ -2,5 +2,5 @@
{% block menu %}
{{ super() }}
- Keyword Index
+ Keyword Index
{% endblock %}
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index f7b3f88e7..d412a2a2e 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -235,7 +235,7 @@ Examples
Given the contract:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -465,17 +465,20 @@ address, a series of up to four topics and some arbitrary length binary data. Ev
ABI in order to interpret this (together with an interface spec) as a properly typed structure.
Given an event name and series of event parameters, we split them into two sub-series: those which are indexed and
-those which are not. Those which are indexed, which may number up to 3, are used alongside the Keccak hash of the
-event signature to form the topics of the log entry. Those which are not indexed form the byte array of the event.
+those which are not.
+Those which are indexed, which may number up to 3 (for non-anonymous events) or 4 (for anonymous ones), are used
+alongside the Keccak hash of the event signature to form the topics of the log entry.
+Those which are not indexed form the byte array of the event.
In effect, a log entry using this ABI is described as:
- ``address``: the address of the contract (intrinsically provided by Ethereum);
- ``topics[0]``: ``keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")")`` (``canonical_type_of``
is a function that simply returns the canonical type of a given argument, e.g. for ``uint indexed foo``, it would
- return ``uint256``). If the event is declared as ``anonymous`` the ``topics[0]`` is not generated;
-- ``topics[n]``: ``abi_encode(EVENT_INDEXED_ARGS[n - 1])`` (``EVENT_INDEXED_ARGS`` is the series of ``EVENT_ARGS``
- that are indexed);
+ return ``uint256``). This value is only present in ``topics[0]`` if the event is not declared as ``anonymous``;
+- ``topics[n]``: ``abi_encode(EVENT_INDEXED_ARGS[n - 1])`` if the event is not declared as ``anonymous``
+ or ``abi_encode(EVENT_INDEXED_ARGS[n])`` if it is (``EVENT_INDEXED_ARGS`` is the series of ``EVENT_ARGS`` that
+ are indexed);
- ``data``: ABI encoding of ``EVENT_NON_INDEXED_ARGS`` (``EVENT_NON_INDEXED_ARGS`` is the series of ``EVENT_ARGS``
that are not indexed, ``abi_encode`` is the ABI encoding function used for returning a series of typed values
from a function, as described above).
@@ -507,7 +510,7 @@ call.
As an example, let us consider the following contract whose ``transfer`` function always
reverts with a custom error of "insufficient balance":
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -596,7 +599,7 @@ Errors look as follows:
For example,
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -650,7 +653,7 @@ which is of array type and has the same structure as the top-level object except
As an example, the code
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.4 <0.9.0;
diff --git a/docs/assembly.rst b/docs/assembly.rst
index d5d73cfb1..4e35ca702 100644
--- a/docs/assembly.rst
+++ b/docs/assembly.rst
@@ -39,7 +39,7 @@ load it into a ``bytes`` variable. This is not possible with "plain Solidity" an
idea is that reusable assembly libraries can enhance the Solidity language
without a compiler change.
-.. code::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -65,7 +65,7 @@ without a compiler change.
Inline assembly is also beneficial in cases where the optimizer fails to produce
efficient code, for example:
-.. code::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -141,7 +141,8 @@ Both expressions can also be assigned to.
Local Solidity variables are available for assignments, for example:
-.. code::
+.. code-block:: solidity
+ :force:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -216,7 +217,9 @@ starting from where this pointer points at and update it.
There is no guarantee that the memory has not been used before and thus
you cannot assume that its contents are zero bytes.
There is no built-in mechanism to release or free allocated memory.
-Here is an assembly snippet you can use for allocating memory that follows the process outlined above::
+Here is an assembly snippet you can use for allocating memory that follows the process outlined above
+
+.. code-block:: yul
function allocate(length) -> pos {
pos := mload(0x40)
diff --git a/docs/bugs.json b/docs/bugs.json
index 36d800b43..5f394aecc 100644
--- a/docs/bugs.json
+++ b/docs/bugs.json
@@ -1,8 +1,10 @@
[
{
+ "uid": "SOL-2021-2",
"name": "ABIDecodeTwoDimensionalArrayMemory",
"summary": "If used on memory byte arrays, result of the function ``abi.decode`` can depend on the contents of memory outside of the actual byte array that is decoded.",
"description": "The ABI specification uses pointers to data areas for everything that is dynamically-sized. When decoding data from memory (instead of calldata), the ABI decoder did not properly validate some of these pointers. More specifically, it was possible to use large values for the pointers inside arrays such that computing the offset resulted in an undetected overflow. This could lead to these pointers targeting areas in memory outside of the actual area to be decoded. This way, it was possible for ``abi.decode`` to return different values for the same encoded byte array.",
+ "link": "https://blog.soliditylang.org/2021/04/21/decoding-from-memory-bug/",
"introduced": "0.4.16",
"fixed": "0.8.4",
"conditions": {
@@ -11,6 +13,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2021-1",
"name": "KeccakCaching",
"summary": "The bytecode optimizer incorrectly re-used previously evaluated Keccak-256 hashes. You are unlikely to be affected if you do not compute Keccak-256 hashes in inline assembly.",
"description": "Solidity's bytecode optimizer has a step that can compute Keccak-256 hashes, if the contents of the memory are known during compilation time. This step also has a mechanism to determine that two Keccak-256 hashes are equal even if the values in memory are not known during compile time. This mechanism had a bug where Keccak-256 of the same memory content, but different sizes were considered equal. More specifically, ``keccak256(mpos1, length1)`` and ``keccak256(mpos2, length2)`` in some cases were considered equal if ``length1`` and ``length2``, when rounded up to nearest multiple of 32 were the same, and when the memory contents at ``mpos1`` and ``mpos2`` can be deduced to be equal. You maybe affected if you compute multiple Keccak-256 hashes of the same content, but with different lengths inside inline assembly. You are unaffected if your code uses ``keccak256`` with a length that is not a compile-time constant or if it is always a multiple of 32.",
@@ -22,20 +25,25 @@
"severity": "medium"
},
{
+ "uid": "SOL-2020-11",
"name": "EmptyByteArrayCopy",
"summary": "Copying an empty byte array (or string) from memory or calldata to storage can result in data corruption if the target array's length is increased subsequently without storing new data.",
"description": "The routine that copies byte arrays from memory or calldata to storage stores unrelated data from after the source array in the storage slot if the source array is empty. If the storage array's length is subsequently increased either by using ``.push()`` or by assigning to its ``.length`` attribute (only before 0.6.0), the newly created byte array elements will not be zero-initialized, but contain the unrelated data. You are not affected if you do not assign to ``.length`` and do not use ``.push()`` on byte arrays, or only use ``.push()`` or manually initialize the new elements.",
+ "link": "https://blog.soliditylang.org/2020/10/19/empty-byte-array-copy-bug/",
"fixed": "0.7.4",
"severity": "medium"
},
{
+ "uid": "SOL-2020-10",
"name": "DynamicArrayCleanup",
"summary": "When assigning a dynamically-sized array with types of size at most 16 bytes in storage causing the assigned array to shrink, some parts of deleted slots were not zeroed out.",
"description": "Consider a dynamically-sized array in storage whose base-type is small enough such that multiple values can be packed into a single slot, such as `uint128[]`. Let us define its length to be `l`. When this array gets assigned from another array with a smaller length, say `m`, the slots between elements `m` and `l` have to be cleaned by zeroing them out. However, this cleaning was not performed properly. Specifically, after the slot corresponding to `m`, only the first packed value was cleaned up. If this array gets resized to a length larger than `m`, the indices corresponding to the unclean parts of the slot contained the original value, instead of 0. The resizing here is performed by assigning to the array `length`, by a `push()` or via inline assembly. You are not affected if you are only using `.push()` or if you assign a value (even zero) to the new elements after increasing the length of the array.",
+ "link": "https://blog.soliditylang.org/2020/10/07/solidity-dynamic-array-cleanup-bug/",
"fixed": "0.7.3",
"severity": "medium"
},
{
+ "uid": "SOL-2020-9",
"name": "FreeFunctionRedefinition",
"summary": "The compiler does not flag an error when two or more free functions with the same name and parameter types are defined in a source unit or when an imported free function alias shadows another free function with a different name but identical parameter types.",
"description": "In contrast to functions defined inside contracts, free functions with identical names and parameter types did not create an error. Both definition of free functions with identical name and parameter types and an imported free function with an alias that shadows another function with a different name but identical parameter types were permitted due to which a call to either the multiply defined free function or the imported free function alias within a contract led to the execution of that free function which was defined first within the source unit. Subsequently defined identical free function definitions were silently ignored and their code generation was skipped.",
@@ -44,6 +52,7 @@
"severity": "low"
},
{
+ "uid": "SOL-2020-8",
"name": "UsingForCalldata",
"summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.",
"description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer. Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption. An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.",
@@ -52,6 +61,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2020-7",
"name": "MissingEscapingInFormatting",
"summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.",
"description": "When ABIEncoderV2 is enabled, string literals passed directly to encoding functions or external function calls are stored as strings in the intemediate code. Characters outside the printable range are handled correctly, but backslashes are not escaped in this procedure. This leads to double backslashes being reduced to single backslashes and consequently re-interpreted as escapes potentially resulting in a different string being encoded.",
@@ -63,6 +73,7 @@
}
},
{
+ "uid": "SOL-2020-6",
"name": "ArraySliceDynamicallyEncodedBaseType",
"summary": "Accessing array slices of arrays with dynamically encoded base types (e.g. multi-dimensional arrays) can result in invalid data being read.",
"description": "For arrays with dynamically sized base types, index range accesses that use a start expression that is non-zero will result in invalid array slices. Any index access to such array slices will result in data being read from incorrect calldata offsets. Array slices are only supported for dynamic calldata types and all problematic type require ABIEncoderV2 to be enabled.",
@@ -74,6 +85,7 @@
}
},
{
+ "uid": "SOL-2020-5",
"name": "ImplicitConstructorCallvalueCheck",
"summary": "The creation code of a contract that does not define a constructor but has a base that does define a constructor did not revert for calls with non-zero value.",
"description": "Starting from Solidity 0.4.5 the creation code of contracts without explicit payable constructor is supposed to contain a callvalue check that results in contract creation reverting, if non-zero value is passed. However, this check was missing in case no explicit constructor was defined in a contract at all, but the contract has a base that does define a constructor. In these cases it is possible to send value in a contract creation transaction or using inline assembly without revert, even though the creation code is supposed to be non-payable.",
@@ -82,6 +94,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2020-4",
"name": "TupleAssignmentMultiStackSlotComponents",
"summary": "Tuple assignments with components that occupy several stack slots, i.e. nested tuples, pointers to external functions or references to dynamically sized calldata arrays, can result in invalid values.",
"description": "Tuple assignments did not correctly account for tuple components that occupy multiple stack slots in case the number of stack slots differs between left-hand-side and right-hand-side. This can either happen in the presence of nested tuples or if the right-hand-side contains external function pointers or references to dynamic calldata arrays, while the left-hand-side contains an omission.",
@@ -90,15 +103,17 @@
"severity": "very low"
},
{
+ "uid": "SOL-2020-3",
"name": "MemoryArrayCreationOverflow",
"summary": "The creation of very large memory arrays can result in overlapping memory regions and thus memory corruption.",
"description": "No runtime overflow checks were performed for the length of memory arrays during creation. In cases for which the memory size of an array in bytes, i.e. the array length times 32, is larger than 2^256-1, the memory allocation will overflow, potentially resulting in overlapping memory areas. The length of the array is still stored correctly, so copying or iterating over such an array will result in out-of-gas.",
- "link": "https://solidity.ethereum.org/2020/04/06/memory-creation-overflow-bug/",
+ "link": "https://blog.soliditylang.org/2020/04/06/memory-creation-overflow-bug/",
"introduced": "0.2.0",
"fixed": "0.6.5",
"severity": "low"
},
{
+ "uid": "SOL-2020-1",
"name": "YulOptimizerRedundantAssignmentBreakContinue",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with ``break`` or ``continue`` even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
@@ -110,6 +125,7 @@
}
},
{
+ "uid": "SOL-2020-2",
"name": "privateCanBeOverridden",
"summary": "Private methods can be overridden by inheriting contracts.",
"description": "While private methods of base contracts are not visible and cannot be called directly from the derived contract, it is still possible to declare a function of the same name and type and thus change the behaviour of the base contract's function.",
@@ -118,6 +134,7 @@
"severity": "low"
},
{
+ "uid": "SOL-2020-1",
"name": "YulOptimizerRedundantAssignmentBreakContinue0.5",
"summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.",
"description": "The Yul optimizer has a stage that removes assignments to variables that are overwritten again or are not used in all following control-flow branches. This logic incorrectly removes such assignments to variables declared inside a for loop if they can be removed in a control-flow branch that ends with ``break`` or ``continue`` even though they cannot be removed in other control-flow branches. Variables declared outside of the respective for loop are not affected.",
@@ -129,6 +146,7 @@
}
},
{
+ "uid": "SOL-2019-10",
"name": "ABIEncoderV2LoopYulOptimizer",
"summary": "If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.",
"description": "The Yul optimizer incorrectly replaces ``mload`` and ``sload`` calls with values that have been previously written to the load location (and potentially changed in the meantime) if all of the following conditions are met: (1) there is a matching ``mstore`` or ``sstore`` call before; (2) the contents of memory or storage is only changed in a function that is called (directly or indirectly) in between the first store and the load call; (3) called function contains a for loop where the same memory location is changed in the condition or the post or body block. When used in Solidity mode, this can only happen if the experimental ABIEncoderV2 is activated and the experimental Yul optimizer has been activated manually in addition to the regular optimizer in the compiler settings.",
@@ -142,6 +160,7 @@
}
},
{
+ "uid": "SOL-2019-9",
"name": "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
"summary": "Reading from calldata structs that contain dynamically encoded, but statically-sized members can result in incorrect values.",
"description": "When a calldata struct contains a dynamically encoded, but statically-sized member, the offsets for all subsequent struct members are calculated incorrectly. All reads from such members will result in invalid values. Only calldata structs are affected, i.e. this occurs in external functions with such structs as argument. Using affected structs in storage or memory or as arguments to public functions on the other hand works correctly.",
@@ -153,19 +172,21 @@
}
},
{
+ "uid": "SOL-2019-8",
"name": "SignedArrayStorageCopy",
"summary": "Assigning an array of signed integers to a storage array of different type can lead to data corruption in that array.",
"description": "In two's complement, negative integers have their higher order bits set. In order to fit into a shared storage slot, these have to be set to zero. When a conversion is done at the same time, the bits to set to zero were incorrectly determined from the source and not the target type. This means that such copy operations can lead to incorrect values being stored.",
- "link": "https://blog.ethereum.org/2019/06/25/solidity-storage-array-bugs/",
+ "link": "https://blog.soliditylang.org/2019/06/25/solidity-storage-array-bugs/",
"introduced": "0.4.7",
"fixed": "0.5.10",
"severity": "low/medium"
},
{
+ "uid": "SOL-2019-7",
"name": "ABIEncoderV2StorageArrayWithMultiSlotElement",
"summary": "Storage arrays containing structs or other statically-sized arrays are not read properly when directly encoded in external function calls or in abi.encode*.",
"description": "When storage arrays whose elements occupy more than a single storage slot are directly encoded in external function calls or using abi.encode*, their elements are read in an overlapping manner, i.e. the element pointer is not properly advanced between reads. This is not a problem when the storage data is first copied to a memory variable or if the storage array only contains value types or dynamically-sized arrays.",
- "link": "https://blog.ethereum.org/2019/06/25/solidity-storage-array-bugs/",
+ "link": "https://blog.soliditylang.org/2019/06/25/solidity-storage-array-bugs/",
"introduced": "0.4.16",
"fixed": "0.5.10",
"severity": "low",
@@ -174,6 +195,7 @@
}
},
{
+ "uid": "SOL-2019-6",
"name": "DynamicConstructorArgumentsClippedABIV2",
"summary": "A contract's constructor that takes structs or arrays that contain dynamically-sized arrays reverts or decodes to invalid data.",
"description": "During construction of a contract, constructor parameters are copied from the code section to memory for decoding. The amount of bytes to copy was calculated incorrectly in case all parameters are statically-sized but contain dynamically-sized arrays as struct members or inner arrays. Such types are only available if ABIEncoderV2 is activated.",
@@ -185,6 +207,7 @@
}
},
{
+ "uid": "SOL-2019-5",
"name": "UninitializedFunctionPointerInConstructor",
"summary": "Calling uninitialized internal function pointers created in the constructor does not always revert and can cause unexpected behaviour.",
"description": "Uninitialized internal function pointers point to a special piece of code that causes a revert when called. Jump target positions are different during construction and after deployment, but the code for setting this special jump target only considered the situation after deployment.",
@@ -193,6 +216,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2019-5",
"name": "UninitializedFunctionPointerInConstructor_0.4.x",
"summary": "Calling uninitialized internal function pointers created in the constructor does not always revert and can cause unexpected behaviour.",
"description": "Uninitialized internal function pointers point to a special piece of code that causes a revert when called. Jump target positions are different during construction and after deployment, but the code for setting this special jump target only considered the situation after deployment.",
@@ -201,6 +225,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2019-4",
"name": "IncorrectEventSignatureInLibraries",
"summary": "Contract types used in events in libraries cause an incorrect event signature hash",
"description": "Instead of using the type `address` in the hashed signature, the actual contract name was used, leading to a wrong hash in the logs.",
@@ -209,6 +234,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2019-4",
"name": "IncorrectEventSignatureInLibraries_0.4.x",
"summary": "Contract types used in events in libraries cause an incorrect event signature hash",
"description": "Instead of using the type `address` in the hashed signature, the actual contract name was used, leading to a wrong hash in the logs.",
@@ -217,10 +243,11 @@
"severity": "very low"
},
{
+ "uid": "SOL-2019-3",
"name": "ABIEncoderV2PackedStorage",
"summary": "Storage structs and arrays with types shorter than 32 bytes can cause data corruption if encoded directly from storage using the experimental ABIEncoderV2.",
"description": "Elements of structs and arrays that are shorter than 32 bytes are not properly decoded from storage when encoded directly (i.e. not via a memory type) using ABIEncoderV2. This can cause corruption in the values themselves but can also overwrite other parts of the encoded data.",
- "link": "https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
+ "link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.5.0",
"fixed": "0.5.7",
"severity": "low",
@@ -229,10 +256,11 @@
}
},
{
+ "uid": "SOL-2019-3",
"name": "ABIEncoderV2PackedStorage_0.4.x",
"summary": "Storage structs and arrays with types shorter than 32 bytes can cause data corruption if encoded directly from storage using the experimental ABIEncoderV2.",
"description": "Elements of structs and arrays that are shorter than 32 bytes are not properly decoded from storage when encoded directly (i.e. not via a memory type) using ABIEncoderV2. This can cause corruption in the values themselves but can also overwrite other parts of the encoded data.",
- "link": "https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
+ "link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.4.19",
"fixed": "0.4.26",
"severity": "low",
@@ -241,10 +269,11 @@
}
},
{
+ "uid": "SOL-2019-2",
"name": "IncorrectByteInstructionOptimization",
"summary": "The optimizer incorrectly handles byte opcodes whose second argument is 31 or a constant expression that evaluates to 31. This can result in unexpected values.",
"description": "The optimizer incorrectly handles byte opcodes that use the constant 31 as second argument. This can happen when performing index access on bytesNN types with a compile-time constant value (not index) of 31 or when using the byte opcode in inline assembly.",
- "link": "https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
+ "link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.5.5",
"fixed": "0.5.7",
"severity": "very low",
@@ -253,10 +282,11 @@
}
},
{
+ "uid": "SOL-2019-1",
"name": "DoubleShiftSizeOverflow",
"summary": "Double bitwise shifts by large constants whose sum overflows 256 bits can result in unexpected values.",
"description": "Nested logical shift operations whose total shift size is 2**256 or more are incorrectly optimized. This only applies to shifts by numbers of bits that are compile-time constant expressions.",
- "link": "https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
+ "link": "https://blog.soliditylang.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/",
"introduced": "0.5.5",
"fixed": "0.5.6",
"severity": "low",
@@ -266,35 +296,39 @@
}
},
{
+ "uid": "SOL-2018-4",
"name": "ExpExponentCleanup",
"summary": "Using the ** operator with an exponent of type shorter than 256 bits can result in unexpected values.",
"description": "Higher order bits in the exponent are not properly cleaned before the EXP opcode is applied if the type of the exponent expression is smaller than 256 bits and not smaller than the type of the base. In that case, the result might be larger than expected if the exponent is assumed to lie within the value range of the type. Literal numbers as exponents are unaffected as are exponents or bases of type uint256.",
- "link": "https://blog.ethereum.org/2018/09/13/solidity-bugfix-release/",
+ "link": "https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/",
"fixed": "0.4.25",
"severity": "medium/high",
"check": {"regex-source": "[^/]\\*\\* *[^/0-9 ]"}
},
{
+ "uid": "SOL-2018-3",
"name": "EventStructWrongData",
"summary": "Using structs in events logged wrong data.",
"description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.",
- "link": "https://blog.ethereum.org/2018/09/13/solidity-bugfix-release/",
+ "link": "https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/",
"introduced": "0.4.17",
"fixed": "0.4.25",
"severity": "very low",
"check": {"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"}
},
{
+ "uid": "SOL-2018-2",
"name": "NestedArrayFunctionCallDecoder",
"summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.",
"description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.",
- "link": "https://blog.ethereum.org/2018/09/13/solidity-bugfix-release/",
+ "link": "https://blog.soliditylang.org/2018/09/13/solidity-bugfix-release/",
"introduced": "0.1.4",
"fixed": "0.4.22",
"severity": "medium",
"check": {"regex-source": "returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]"}
},
{
+ "uid": "SOL-2018-1",
"name": "OneOfTwoConstructorsSkipped",
"summary": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.",
"description": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored. There will be a compiler warning about the old-style constructor, so contracts only using new-style constructors are fine.",
@@ -303,6 +337,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2017-5",
"name": "ZeroFunctionSelector",
"summary": "It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.",
"description": "If a function has a selector consisting only of zeros, is payable and part of a contract that does not have a fallback function and at most five external functions in total, this function is called instead of the fallback function if Ether is sent to the contract without data.",
@@ -310,6 +345,7 @@
"severity": "very low"
},
{
+ "uid": "SOL-2017-4",
"name": "DelegateCallReturnValue",
"summary": "The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.",
"description": "The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides. This value is interpreted as a boolean and put onto the stack. This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successful.",
@@ -318,6 +354,7 @@
"severity": "low"
},
{
+ "uid": "SOL-2017-3",
"name": "ECRecoverMalformedInput",
"summary": "The ecrecover() builtin can return garbage for malformed input.",
"description": "The ecrecover precompile does not properly signal failure for malformed input (especially in the 'v' argument) and thus the Solidity function can return data that was previously present in the return area in memory.",
@@ -325,6 +362,7 @@
"severity": "medium"
},
{
+ "uid": "SOL-2017-2",
"name": "SkipEmptyStringLiteral",
"summary": "If \"\" is used in a function call, the following function arguments will not be correctly passed to the function.",
"description": "If the empty string literal \"\" is used as an argument in a function call, it is skipped by the encoder. This has the effect that the encoding of all arguments following this is shifted left by 32 bytes and thus the function call data is corrupted.",
@@ -332,10 +370,11 @@
"severity": "low"
},
{
+ "uid": "SOL-2017-1",
"name": "ConstantOptimizerSubtraction",
"summary": "In some situations, the optimizer replaces certain numbers in the code with routines that compute different numbers.",
"description": "The optimizer tries to represent any number in the bytecode by routines that compute them with less gas. For some special numbers, an incorrect routine is generated. This could allow an attacker to e.g. trick victims about a specific amount of ether, or function calls to call different functions (or none at all).",
- "link": "https://blog.ethereum.org/2017/05/03/solidity-optimizer-bug/",
+ "link": "https://blog.soliditylang.org/2017/05/03/solidity-optimizer-bug/",
"fixed": "0.4.11",
"severity": "low",
"conditions": {
@@ -343,6 +382,7 @@
}
},
{
+ "uid": "SOL-2016-11",
"name": "IdentityPrecompileReturnIgnored",
"summary": "Failure of the identity precompile was ignored.",
"description": "Calls to the identity contract, which is used for copying memory, ignored its return value. On the public chain, calls to the identity precompile can be made in a way that they never fail, but this might be different on private chains.",
@@ -350,6 +390,7 @@
"fixed": "0.4.7"
},
{
+ "uid": "SOL-2016-10",
"name": "OptimizerStateKnowledgeNotResetForJumpdest",
"summary": "The optimizer did not properly reset its internal state at jump destinations, which could lead to data corruption.",
"description": "The optimizer performs symbolic execution at certain stages. At jump destinations, multiple code paths join and thus it has to compute a common state from the incoming edges. Computing this common state was simplified to just use the empty state, but this implementation was not done properly. This bug can cause data corruption.",
@@ -361,15 +402,17 @@
}
},
{
+ "uid": "SOL-2016-9",
"name": "HighOrderByteCleanStorage",
"summary": "For short types, the high order bytes were not cleaned properly and could overwrite existing data.",
"description": "Types shorter than 32 bytes are packed together into the same 32 byte storage slot, but storage writes always write 32 bytes. For some types, the higher order bytes were not cleaned properly, which made it sometimes possible to overwrite a variable in storage when writing to another one.",
- "link": "https://blog.ethereum.org/2016/11/01/security-alert-solidity-variables-can-overwritten-storage/",
+ "link": "https://blog.soliditylang.org/2016/11/01/security-alert-solidity-variables-can-overwritten-storage/",
"severity": "high",
"introduced": "0.1.6",
"fixed": "0.4.4"
},
{
+ "uid": "SOL-2016-8",
"name": "OptimizerStaleKnowledgeAboutSHA3",
"summary": "The optimizer did not properly reset its knowledge about SHA3 operations resulting in some hashes (also used for storage variable positions) not being calculated correctly.",
"description": "The optimizer performs symbolic execution in order to save re-evaluating expressions whose value is already known. This knowledge was not properly reset across control flow paths and thus the optimizer sometimes thought that the result of a SHA3 operation is already present on the stack. This could result in data corruption by accessing the wrong storage slot.",
@@ -380,6 +423,7 @@
}
},
{
+ "uid": "SOL-2016-7",
"name": "LibrariesNotCallableFromPayableFunctions",
"summary": "Library functions threw an exception when called from a call that received Ether.",
"description": "Library functions are protected against sending them Ether through a call. Since the DELEGATECALL opcode forwards the information about how much Ether was sent with a call, the library function incorrectly assumed that Ether was sent to the library and threw an exception.",
@@ -388,6 +432,7 @@
"fixed": "0.4.2"
},
{
+ "uid": "SOL-2016-6",
"name": "SendFailsForZeroEther",
"summary": "The send function did not provide enough gas to the recipient if no Ether was sent with it.",
"description": "The recipient of an Ether transfer automatically receives a certain amount of gas from the EVM to handle the transfer. In the case of a zero-transfer, this gas is not provided which causes the recipient to throw an exception.",
@@ -395,6 +440,7 @@
"fixed": "0.4.0"
},
{
+ "uid": "SOL-2016-5",
"name": "DynamicAllocationInfiniteLoop",
"summary": "Dynamic allocation of an empty memory array caused an infinite loop and thus an exception.",
"description": "Memory arrays can be created provided a length. If this length is zero, code was generated that did not terminate and thus consumed all gas.",
@@ -402,6 +448,7 @@
"fixed": "0.3.6"
},
{
+ "uid": "SOL-2016-4",
"name": "OptimizerClearStateOnCodePathJoin",
"summary": "The optimizer did not properly reset its internal state at jump destinations, which could lead to data corruption.",
"description": "The optimizer performs symbolic execution at certain stages. At jump destinations, multiple code paths join and thus it has to compute a common state from the incoming edges. Computing this common state was not done correctly. This bug can cause data corruption, but it is probably quite hard to use for targeted attacks.",
@@ -412,6 +459,7 @@
}
},
{
+ "uid": "SOL-2016-3",
"name": "CleanBytesHigherOrderBits",
"summary": "The higher order bits of short bytesNN types were not cleaned before comparison.",
"description": "Two variables of type bytesNN were considered different if their higher order bits, which are not part of the actual value, were different. An attacker might use this to reach seemingly unreachable code paths by providing incorrectly formatted input data.",
@@ -419,6 +467,7 @@
"fixed": "0.3.3"
},
{
+ "uid": "SOL-2016-2",
"name": "ArrayAccessCleanHigherOrderBits",
"summary": "Access to array elements for arrays of types with less than 32 bytes did not correctly clean the higher order bits, causing corruption in other array elements.",
"description": "Multiple elements of an array of values that are shorter than 17 bytes are packed into the same storage slot. Writing to a single element of such an array did not properly clean the higher order bytes and thus could lead to data corruption.",
@@ -426,6 +475,7 @@
"fixed": "0.3.1"
},
{
+ "uid": "SOL-2016-1",
"name": "AncientCompiler",
"summary": "This compiler version is ancient and might contain several undocumented or undiscovered bugs.",
"description": "The list of bugs is only kept for compiler versions starting from 0.3.0, so older versions might contain undocumented bugs.",
diff --git a/docs/bugs.rst b/docs/bugs.rst
index 11680abcd..73700adf3 100644
--- a/docs/bugs.rst
+++ b/docs/bugs.rst
@@ -33,6 +33,10 @@ contracts should consult this list according to the following criteria:
The JSON file of known bugs below is an array of objects, one for each bug,
with the following keys:
+uid
+ Unique identifier given to the bug in the form of ``SOL--``.
+ It is possible that multiple entries exists with the same uid. This means
+ multiple version ranges are affected by the same bug.
name
Unique name given to the bug
summary
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index dd6706872..9f708595d 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -1543,5 +1543,13 @@
"0.8.4": {
"bugs": [],
"released": "2021-04-21"
+ },
+ "0.8.5": {
+ "bugs": [],
+ "released": "2021-06-10"
+ },
+ "0.8.6": {
+ "bugs": [],
+ "released": "2021-06-22"
}
}
\ No newline at end of file
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst
index a7b276661..58fb39ea2 100644
--- a/docs/common-patterns.rst
+++ b/docs/common-patterns.rst
@@ -25,7 +25,7 @@ contract in order to become the "richest", inspired by
In the following contract, if you are no longer the richest,
you receive the funds of the person who is now the richest.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -63,7 +63,7 @@ you receive the funds of the person who is now the richest.
This is as opposed to the more intuitive sending pattern:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -129,7 +129,7 @@ functions and this is what this section is about.
The use of **function modifiers** makes these
restrictions highly readable.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -292,7 +292,7 @@ function finishes.
Starting with version 0.4.0, modifier code
will run even if the function explicitly returns.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
diff --git a/docs/conf.py b/docs/conf.py
index f0eb06e4d..4c7a67164 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -26,10 +26,10 @@ from pygments_lexer_solidity import SolidityLexer, YulLexer
def setup(sphinx):
thisdir = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, thisdir + '/utils')
- sphinx.add_lexer('Solidity', SolidityLexer())
- sphinx.add_lexer('Yul', YulLexer())
+ sphinx.add_lexer('Solidity', SolidityLexer)
+ sphinx.add_lexer('Yul', YulLexer)
- sphinx.add_stylesheet('css/custom.css')
+ sphinx.add_css_file('css/custom.css')
# -- General configuration ------------------------------------------------
diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst
index 8467337af..34792f58c 100644
--- a/docs/contracts/abstract-contracts.rst
+++ b/docs/contracts/abstract-contracts.rst
@@ -11,7 +11,9 @@ Contracts may be marked as abstract even though all functions are implemented.
This can be done by using the ``abstract`` keyword as shown in the following example. Note that this contract needs to be
defined as abstract, because the function ``utterance()`` was defined, but no implementation was
-provided (no implementation body ``{ }`` was given).::
+provided (no implementation body ``{ }`` was given).
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -21,7 +23,9 @@ provided (no implementation body ``{ }`` was given).::
}
Such abstract contracts can not be instantiated directly. This is also true, if an abstract contract itself does implement
-all defined functions. The usage of an abstract contract as a base class is shown in the following example::
+all defined functions. The usage of an abstract contract as a base class is shown in the following example:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -40,11 +44,15 @@ functions by overriding, it needs to be marked as abstract as well.
Note that a function without implementation is different from
a :ref:`Function Type ` even though their syntax looks very similar.
-Example of function without implementation (a function declaration)::
+Example of function without implementation (a function declaration):
+
+.. code-block:: solidity
function foo(address) external returns (address);
-Example of a declaration of a variable whose type is a function type::
+Example of a declaration of a variable whose type is a function type:
+
+.. code-block:: solidity
function(address) external returns (address) foo;
diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst
index d22735618..01a4f164c 100644
--- a/docs/contracts/constant-state-variables.rst
+++ b/docs/contracts/constant-state-variables.rst
@@ -27,7 +27,7 @@ can sometimes be cheaper than immutable values.
Not all types for constants and immutables are implemented at this time. The only supported types are
:ref:`strings ` (only for constants) and :ref:`value types `.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.4;
diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst
index d93ac832c..f1fd3b0b5 100644
--- a/docs/contracts/creating-contracts.rst
+++ b/docs/contracts/creating-contracts.rst
@@ -32,7 +32,7 @@ If a contract wants to create another contract, the source code
(and the binary) of the created contract has to be known to the creator.
This means that cyclic creation dependencies are impossible.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
diff --git a/docs/contracts/errors.rst b/docs/contracts/errors.rst
index 3ae9a57f1..7800317a8 100644
--- a/docs/contracts/errors.rst
+++ b/docs/contracts/errors.rst
@@ -14,7 +14,7 @@ which causes
all changes in the current call to be reverted and passes the error data back to the
caller.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -79,4 +79,4 @@ of the built-in type ``Panic(uint256)``.
of inner calls is propagated back through the chain of external calls
by default. This means that an inner call
can "forge" revert data that looks like it could have come from the
- contract that called it.
\ No newline at end of file
+ contract that called it.
diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst
index e9a520e3c..aae16fb8b 100644
--- a/docs/contracts/events.rst
+++ b/docs/contracts/events.rst
@@ -24,9 +24,10 @@ because the contract can only see the last 256 block hashes.
You can add the attribute ``indexed`` to up to three parameters which adds them
to a special data structure known as :ref:`"topics" ` instead of
-the data part of the log. If you use arrays (including ``string`` and ``bytes``)
-as indexed arguments, its Keccak-256 hash is stored as a topic instead, this is
-because a topic can only hold a single word (32 bytes).
+the data part of the log.
+A topic can only hold a single word (32 bytes) so if you use a :ref:`reference type
+` for an indexed argument, the Keccak-256 hash of the value is stored
+as a topic instead.
All parameters without the ``indexed`` attribute are :ref:`ABI-encoded `
into the data part of the log.
@@ -61,7 +62,16 @@ The hash of the signature of the event is one of the topics, except if you
declared the event with the ``anonymous`` specifier. This means that it is
not possible to filter for specific anonymous events by name, you can
only filter by the contract address. The advantage of anonymous events
-is that they are cheaper to deploy and call.
+is that they are cheaper to deploy and call. It also allows you to declare
+four indexed arguments rather than three.
+
+.. note::
+ Since the transaction log only stores the event data and not the type,
+ you have to know the type of the event, including which parameter is
+ indexed and if the event is anonymous in order to correctly interpret
+ the data.
+ In particular, it is possible to "fake" the signature of another event
+ using an anonymous event.
::
diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst
index 86aba6b33..262d80321 100644
--- a/docs/contracts/function-modifiers.rst
+++ b/docs/contracts/function-modifiers.rst
@@ -15,7 +15,7 @@ inheritable properties of contracts and may be overridden by derived contracts,
if they are marked ``virtual``. For details, please see
:ref:`Modifier Overriding `.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0 <0.9.0;
diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst
index 6f525a7b1..56bc85a05 100644
--- a/docs/contracts/functions.rst
+++ b/docs/contracts/functions.rst
@@ -12,7 +12,7 @@ Functions outside of a contract, also called "free functions", always have impli
:ref:`visibility`. Their code is included in all contracts
that call them, similar to internal library functions.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0 <0.9.0;
@@ -56,7 +56,9 @@ Function parameters are declared the same way as variables, and the name of
unused parameters can be omitted.
For example, if you want your contract to accept one kind of external call
-with two integers, you would use something like the following::
+with two integers, you would use something like the following:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -89,7 +91,9 @@ Function return variables are declared with the same syntax after the
``returns`` keyword.
For example, suppose you want to return two results: the sum and the product of
-two integers passed as function parameters, then you use something like::
+two integers passed as function parameters, then you use something like:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -114,7 +118,9 @@ You can either explicitly assign to return variables and
then leave the function as above,
or you can provide return values
(either a single or :ref:`multiple ones`) directly with the ``return``
-statement::
+statement:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -178,7 +184,7 @@ The following statements are considered modifying the state:
#. Using low-level calls.
#. Using inline assembly that contains certain opcodes.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -224,7 +230,7 @@ In addition to the list of state modifying statements explained above, the follo
#. Calling any function not marked ``pure``.
#. Using inline assembly that contains certain opcodes.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -321,7 +327,7 @@ will consume more gas than the 2300 gas stipend:
Below you can see an example of a Sink contract that uses function ``receive``.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -383,7 +389,7 @@ operations as long as there is enough gas passed on to it.
proper functions should be used instead.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;
@@ -461,7 +467,7 @@ This process is called "overloading" and also applies to inherited functions.
The following example shows overloading of the function
``f`` in the scope of contract ``A``.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -480,7 +486,7 @@ The following example shows overloading of the function
Overloaded functions are also present in the external interface. It is an error if two
externally visible functions differ by their Solidity types but not by their external types.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -514,7 +520,7 @@ candidate, resolution fails.
.. note::
Return parameters are not taken into account for overload resolution.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst
index 5beb226bd..24d2fd2ff 100644
--- a/docs/contracts/inheritance.rst
+++ b/docs/contracts/inheritance.rst
@@ -36,7 +36,7 @@ some :ref:`differences `.
Details are given in the following example.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -124,7 +124,9 @@ Details are given in the following example.
Note that above, we call ``Destructible.destroy()`` to "forward" the
destruction request. The way this is done is problematic, as
-seen in the following example::
+seen in the following example:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -154,7 +156,9 @@ seen in the following example::
A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it
explicitly in the final override, but this function will bypass
-``Base1.destroy``. The way around this is to use ``super``::
+``Base1.destroy``. The way around this is to use ``super``:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -211,7 +215,7 @@ The mutability may be changed to a more strict one following the order:
The following example demonstrates changing mutability and visibility:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -235,7 +239,7 @@ and have not yet been overridden by another base contract (on some path through
Additionally, if a contract inherits the same function from multiple (unrelated)
bases, it has to explicitly override it:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -262,7 +266,7 @@ the function is defined in a common base contract
or if there is a unique function in a common base contract
that already overrides all other functions.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -303,7 +307,7 @@ Public state variables can override external functions if the
parameter and return types of the function matches the getter function
of the variable:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -335,7 +339,7 @@ Function modifiers can override each other. This works in the same way as
``virtual`` keyword must be used on the overridden modifier
and the ``override`` keyword must be used in the overriding modifier:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -354,7 +358,7 @@ and the ``override`` keyword must be used in the overriding modifier:
In case of multiple inheritance, all direct base contracts must be specified
explicitly:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -402,7 +406,7 @@ If there is no
constructor, the contract will assume the default constructor, which is
equivalent to ``constructor() {}``. For example:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -439,7 +443,9 @@ Arguments for Base Constructors
The constructors of all the base contracts will be called following the
linearization rules explained below. If the base constructors have arguments,
-derived contracts need to specify all of them. This can be done in two ways::
+derived contracts need to specify all of them. This can be done in two ways:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -499,7 +505,7 @@ stopping at the first match. If a base contract has already been searched, it is
In the following code, Solidity will give the
error "Linearization of inheritance graph impossible".
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -520,7 +526,7 @@ C3 linearization is not too important in practice.
One area where inheritance linearization is especially important and perhaps not as clear is when there are multiple constructors in the inheritance hierarchy. The constructors will always be executed in the linearized order, regardless of the order in which their arguments are provided in the inheriting contract's constructor. For example:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst
index 19a33605e..bfaf1bf2e 100644
--- a/docs/contracts/interfaces.rst
+++ b/docs/contracts/interfaces.rst
@@ -20,7 +20,7 @@ an interface should be possible without any information loss.
Interfaces are denoted by their own keyword:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;
@@ -41,7 +41,7 @@ function is marked ``virtual``.
Interfaces can inherit from other interfaces. This has the same rules as normal
inheritance.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;
diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst
index 88e13d90c..eee9de765 100644
--- a/docs/contracts/libraries.rst
+++ b/docs/contracts/libraries.rst
@@ -50,7 +50,7 @@ The following example illustrates how to use libraries (but using a manual metho
be sure to check out :ref:`using for ` for a
more advanced example to implement a set).
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -129,7 +129,7 @@ The following example shows how to use :ref:`types stored in memory =0.6.8 <0.9.0;
@@ -238,7 +238,7 @@ The argument encoding is the same as for the regular contract ABI, except for st
Similarly to the contract ABI, the selector consists of the first four bytes of the Keccak256-hash of the signature.
Its value can be obtained from Solidity using the ``.selector`` member as follows:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.14 <0.9.0;
diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst
index 19cdf8e61..582409904 100644
--- a/docs/contracts/using-for.rst
+++ b/docs/contracts/using-for.rst
@@ -27,7 +27,9 @@ outside of the contract in which it is used. The directive
may only be used inside a contract, not inside any of its functions.
Let us rewrite the set example from the
-:ref:`libraries` in this way::
+:ref:`libraries` in this way:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -80,7 +82,9 @@ Let us rewrite the set example from the
}
}
-It is also possible to extend elementary types in that way::
+It is also possible to extend elementary types in that way:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.8 <0.9.0;
diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst
index d353c1911..a865f54d4 100644
--- a/docs/contracts/visibility-and-getters.rst
+++ b/docs/contracts/visibility-and-getters.rst
@@ -50,7 +50,7 @@ The visibility specifier is given after the type for
state variables and between parameter list and
return parameter list for functions.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -65,7 +65,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value
``data`` in state storage, but is not able to call ``f``. Contract ``E`` is derived from
``C`` and, thus, can call ``compute``.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -110,7 +110,7 @@ arguments and returns a ``uint``, the value of the state
variable ``data``. State variables can be initialized
when they are declared.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -131,7 +131,7 @@ symbol is accessed internally (i.e. without ``this.``),
it evaluates to a state variable. If it is accessed externally
(i.e. with ``this.``), it evaluates to a function.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -148,10 +148,10 @@ If you have a ``public`` state variable of array type, then you can only retriev
single elements of the array via the generated getter function. This mechanism
exists to avoid high gas costs when returning an entire array. You can use
arguments to specify which individual element to return, for example
-``data(0)``. If you want to return an entire array in one call, then you need
+``myArray(0)``. If you want to return an entire array in one call, then you need
to write a function, for example:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -178,7 +178,7 @@ Now you can use ``getArray()`` to retrieve the entire array, instead of
The next example is more complex:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -195,7 +195,7 @@ The next example is more complex:
It generates a function of the following form. The mapping in the struct is omitted
because there is no good way to provide the key for the mapping:
-::
+.. code-block:: solidity
function data(uint arg1, bool arg2, uint arg3) public returns (uint a, bytes3 b) {
a = data[arg1][arg2][arg3].a;
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 0c084c264..eaae6db3e 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -112,7 +112,7 @@ starting from the current directory. The required file is called ``libevmone.so`
``evmone.dll`` on Windows systems and ``libevmone.dylib`` on macOS. If it is not found, tests that
use it are skipped. These tests are ``libsolididty/semanticTests``, ``libsolidity/GasCosts``,
``libsolidity/SolidityEndToEndTest``, part of the soltest suite. To run all tests, download the library from
-`GitHub `_
+`GitHub `_
and place it in the project root path or inside the ``deps`` folder.
If the ``libz3`` library is not installed on your system, you should disable the
@@ -149,7 +149,7 @@ See especially:
If you want to debug using GDB, make sure you build differently than the "usual".
For example, you could run the following command in your ``build`` folder:
-::
+.. code-block:: bash
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
@@ -171,7 +171,7 @@ The test suite compiles and checks them against the given expectations.
For example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol``
-::
+.. code-block:: solidity
contract test {
uint256 variable;
@@ -190,7 +190,7 @@ In the above example, the state variable ``variable`` was declared twice, which
The ``isoltest`` tool is used for these tests and you can find it under ``./build/test/tools/``. It is an interactive tool which allows
editing of failing contracts using your preferred text editor. Let's try to break this test by removing the second declaration of ``variable``:
-::
+.. code-block:: solidity
contract test {
uint256 variable;
@@ -200,7 +200,7 @@ editing of failing contracts using your preferred text editor. Let's try to brea
Running ``./build/test/isoltest`` again results in a test failure:
-::
+.. code-block:: text
syntaxTests/double_stateVariable_declaration.sol: FAIL
Contract:
@@ -228,7 +228,7 @@ All of these options apply to the current contract, expect ``quit`` which stops
Automatically updating the test above changes it to
-::
+.. code-block:: solidity
contract test {
uint256 variable;
@@ -237,7 +237,7 @@ Automatically updating the test above changes it to
and re-run the test. It now passes again:
-::
+.. code-block:: text
Re-running test case...
syntaxTests/double_stateVariable_declaration.sol: OK
@@ -263,7 +263,7 @@ We mainly use `AFL `_ for fuzzing. You need to
install the AFL packages from your repositories (afl, afl-clang) or build them manually.
Next, build Solidity (or just the ``solfuzzer`` binary) with AFL as your compiler:
-::
+.. code-block:: bash
cd build
# if needed
@@ -273,7 +273,7 @@ Next, build Solidity (or just the ``solfuzzer`` binary) with AFL as your compile
At this stage you should be able to see a message similar to the following:
-::
+.. code-block:: text
Scanning dependencies of target solfuzzer
[ 98%] Building CXX object test/tools/CMakeFiles/solfuzzer.dir/fuzzer.cpp.o
@@ -284,7 +284,7 @@ At this stage you should be able to see a message similar to the following:
If the instrumentation messages did not appear, try switching the cmake flags pointing to AFL's clang binaries:
-::
+.. code-block:: bash
# if previously failed
make clean
@@ -293,7 +293,7 @@ If the instrumentation messages did not appear, try switching the cmake flags po
Otherwise, upon execution the fuzzer halts with an error saying binary is not instrumented:
-::
+.. code-block:: text
afl-fuzz 2.52b by
... (truncated messages)
@@ -317,7 +317,7 @@ Next, you need some example source files. This makes it much easier for the fuzz
to find errors. You can either copy some files from the syntax tests or extract test files
from the documentation or the other tests:
-::
+.. code-block:: bash
mkdir /tmp/test_cases
cd /tmp/test_cases
@@ -334,7 +334,7 @@ that result in similar behaviour of the binary.
Now run the fuzzer (the ``-m`` extends the size of memory to 60 MB):
-::
+.. code-block:: bash
afl-fuzz -m 60 -i /tmp/test_cases -o /tmp/fuzzer_reports -- /path/to/solfuzzer
@@ -388,7 +388,8 @@ local slang and references, making your language as clear to all readers as poss
.. note::
While the official Solidity documentation is written in English, there are community contributed :ref:`translations`
- in other languages available.
+ in other languages available. Please refer to the `translation guide `_
+ for information on how to contribute to the community translations.
Title Case for Headings
-----------------------
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index f9d52148f..9da26ca26 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -39,11 +39,14 @@ Internal Function Calls
-----------------------
Functions of the current contract can be called directly ("internally"), also recursively, as seen in
-this nonsensical example::
+this nonsensical example:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
+ // This will report a warning
contract C {
function g(uint a) public pure returns (uint ret) { return a + f(); }
function f() internal pure returns (uint ret) { return g(7) + f(); }
@@ -81,7 +84,7 @@ Note that it is discouraged to specify gas values explicitly, since the gas cost
of opcodes can change in the future. Any Wei you send to the contract is added
to the total balance of that contract:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;
@@ -143,7 +146,7 @@ if they are enclosed in ``{ }`` as can be seen in the following
example. The argument list has to coincide by name with the list of
parameters from the function declaration, but can be in arbitrary order.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -167,7 +170,7 @@ Omitted Function Parameter Names
The names of unused parameters (especially return parameters) can be omitted.
Those parameters will still be present on the stack, but they are inaccessible.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
@@ -191,7 +194,7 @@ A contract can create other contracts using the ``new`` keyword. The full
code of the contract being created has to be known when the creating contract
is compiled so recursive creation-dependencies are not possible.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -246,7 +249,7 @@ contracts creates other contracts in the meantime.
The main use-case here is contracts that act as judges for off-chain interactions,
which only need to be created if there is a dispute.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -315,7 +318,7 @@ or to pre-existing variables (or LValues in general).
Tuples are not proper types in Solidity, they can only be used to form syntactic
groupings of expressions.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -361,7 +364,7 @@ In the example below the call to ``g(x)`` has no effect on ``x`` because it crea
an independent copy of the storage value in memory. However, ``h(x)`` successfully modifies ``x``
because only a reference and not a copy is passed.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
@@ -420,7 +423,7 @@ use state variables before they are declared and call functions recursively.
As a consequence, the following examples will compile without warnings, since
the two variables have the same name but disjoint scopes.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -442,7 +445,7 @@ As a special example of the C99 scoping rules, note that in the following,
the first assignment to ``x`` will actually assign the outer and not the inner variable.
In any case, you will get a warning about the outer variable being shadowed.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -464,7 +467,7 @@ In any case, you will get a warning about the outer variable being shadowed.
for the entire function, regardless where it was declared. The following example shows a code snippet that used
to compile but leads to an error starting from version 0.5.0.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -496,7 +499,7 @@ thus making the use of these libraries unnecessary.
To obtain the previous behaviour, an ``unchecked`` block can be used:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
@@ -598,6 +601,7 @@ function calls which will cause a Panic.
A Panic exception is generated in the following situations.
The error code supplied with the error data indicates the kind of panic.
+#. 0x00: Used for generic compiler inserted panics.
#. 0x01: If you call ``assert`` with an argument that evaluates to false.
#. 0x11: If an arithmetic operation results in underflow or overflow outside of an ``unchecked { ... }`` block.
#. 0x12; If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
@@ -655,7 +659,7 @@ You can optionally provide a message string for ``require``, but not for ``asser
The following example shows how you can use ``require`` to check conditions on inputs
and ``assert`` for internal error checking.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -719,7 +723,7 @@ any costs.
The following example shows how to use an error string and a custom error instance
together with ``revert`` and the equivalent ``require``:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -779,7 +783,7 @@ The provided message can be retrieved by the caller using ``try``/``catch`` as s
A failure in an external call can be caught using a try/catch statement, as follows:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.8.0;
diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst
index 802b4d171..ce72cdf18 100644
--- a/docs/examples/blind-auction.rst
+++ b/docs/examples/blind-auction.rst
@@ -22,7 +22,7 @@ raised, the previous highest bidder gets their money back. After the end of
the bidding period, the contract has to be called manually for the beneficiary
to receive their money - contracts cannot activate themselves.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -191,7 +191,7 @@ transfers): Bidders can confuse competition by placing several high or low
invalid bids.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst
index 09f5324b6..b9030747b 100644
--- a/docs/examples/micropayment.rst
+++ b/docs/examples/micropayment.rst
@@ -40,7 +40,7 @@ using `web3.js `_ and
`MetaMask `_, using the method described in `EIP-762 `_,
as it provides a number of other security benefits.
-::
+.. code-block:: javascript
/// Hashing first makes things easier
var hash = web3.utils.sha3("message to sign");
@@ -90,7 +90,7 @@ library provides a function called ``soliditySHA3`` that mimics the behaviour of
Solidity's ``keccak256`` function applied to arguments encoded using ``abi.encodePacked``.
Here is a JavaScript function that creates the proper signature for the ``ReceiverPays`` example:
-::
+.. code-block:: javascript
// recipient is the address that should be paid.
// amount, in wei, specifies how much ether should be sent.
@@ -139,7 +139,8 @@ The functions ``prefixed`` and ``recoverSigner`` do this in the ``claimPayment``
The full contract
-----------------
-::
+.. code-block:: solidity
+ :force:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -271,7 +272,7 @@ to prevent a message intended for one payment channel from being used for a diff
Here is the modified JavaScript code to cryptographically sign a message from the previous section:
-::
+.. code-block:: javascript
function constructPaymentMessage(contractAddress, amount) {
return abi.soliditySHA3(
@@ -335,7 +336,8 @@ so it is important that Bob closes the channel before the expiration is reached.
The full contract
-----------------
-::
+.. code-block:: solidity
+ :force:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -452,9 +454,9 @@ The recipient should verify each message using the following process:
We'll use the `ethereumjs-util `_
library to write this verification. The final step can be done a number of ways,
-and we use JavaScript. The following code borrows the ``constructMessage`` function from the signing **JavaScript code** above:
+and we use JavaScript. The following code borrows the ``constructPaymentMessage`` function from the signing **JavaScript code** above:
-::
+.. code-block:: javascript
// this mimics the prefixing behavior of the eth_sign JSON-RPC method.
function prefixed(hash) {
diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst
index 5ad6a691d..d91a744d4 100644
--- a/docs/examples/modular.rst
+++ b/docs/examples/modular.rst
@@ -17,7 +17,7 @@ provides an isolated component that properly tracks balances of accounts.
It is easy to verify that the ``Balances`` library never produces negative balances or overflows
and the sum of all balances is an invariant across the lifetime of the contract.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst
index 5a24e5a8f..4c6dab1be 100644
--- a/docs/examples/safe-remote.rst
+++ b/docs/examples/safe-remote.rst
@@ -23,7 +23,7 @@ This contract of course does not solve the problem, but gives an overview of how
you can use state machine-like constructs inside a contract.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
diff --git a/docs/examples/voting.rst b/docs/examples/voting.rst
index 299816fd9..2c229041f 100644
--- a/docs/examples/voting.rst
+++ b/docs/examples/voting.rst
@@ -30,7 +30,7 @@ At the end of the voting time, ``winningProposal()``
will return the proposal with the largest number
of votes.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
diff --git a/docs/index.rst b/docs/index.rst
index cb9fd6479..44ddbff83 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -91,6 +91,12 @@ Community volunteers help translate this documentation into several languages.
They have varying degrees of completeness and up-to-dateness. The English
version stands as a reference.
+.. note::
+
+ We recently set up a new GitHub organization and translation workflow to help streamline the
+ community efforts. Please refer to the `translation guide `_
+ for information on how to contribute to the community translations moving forward.
+
* `French `_ (in progress)
* `Italian `_ (in progress)
* `Japanese `_
@@ -143,7 +149,7 @@ Contents
internals/layout_in_calldata.rst
internals/variable_cleanup.rst
internals/source_mappings.rst
- internals/optimiser.rst
+ internals/optimizer.rst
metadata.rst
abi-spec.rst
@@ -160,6 +166,7 @@ Contents
security-considerations.rst
smtchecker.rst
resources.rst
+ path-resolution.rst
yul.rst
style-guide.rst
common-patterns.rst
diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst
index 7c676ff90..a0857e038 100644
--- a/docs/installing-solidity.rst
+++ b/docs/installing-solidity.rst
@@ -86,7 +86,9 @@ local folder for input and output, and specify the contract to compile. For exam
docker run -v /local/path:/sources ethereum/solc:stable -o /sources/output --abi --bin /sources/Contract.sol
You can also use the standard JSON interface (which is recommended when using the compiler with tooling).
-When using this interface it is not necessary to mount any directories.
+When using this interface it is not necessary to mount any directories as long as the JSON input is
+self-contained (i.e. it does not refer to any external files that would have to be
+:ref:`loaded by the import callback `).
.. code-block:: bash
diff --git a/docs/internals/layout_in_memory.rst b/docs/internals/layout_in_memory.rst
index bad8c1654..66623572f 100644
--- a/docs/internals/layout_in_memory.rst
+++ b/docs/internals/layout_in_memory.rst
@@ -49,7 +49,7 @@ Example for Difference in Arrays
The following array occupies 32 bytes (1 slot) in storage, but 128
bytes (4 items with 32 bytes each) in memory.
-::
+.. code-block:: solidity
uint8[4] a;
@@ -62,7 +62,7 @@ The following struct occupies 96 bytes (3 slots of 32 bytes) in storage,
but 128 bytes (4 items with 32 bytes each) in memory.
-::
+.. code-block:: solidity
struct S {
uint a;
diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst
index 68373dbd4..a9de8f6c9 100644
--- a/docs/internals/layout_in_storage.rst
+++ b/docs/internals/layout_in_storage.rst
@@ -98,7 +98,7 @@ for example, you have to add an offset corresponding to the struct member to rea
As an example, consider the following contract:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -216,7 +216,7 @@ The following example shows a contract and its storage layout, containing
value and reference types, types that are encoded packed, and nested types.
-.. code::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -238,12 +238,12 @@ value and reference types, types that are encoded packed, and nested types.
bytes b1;
}
-.. code::
+.. code:: json
- "storageLayout": {
+ {
"storage": [
{
- "astId": 14,
+ "astId": 15,
"contract": "fileA:A",
"label": "x",
"offset": 0,
@@ -251,7 +251,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_uint256"
},
{
- "astId": 16,
+ "astId": 17,
"contract": "fileA:A",
"label": "y",
"offset": 0,
@@ -259,15 +259,15 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_uint256"
},
{
- "astId": 18,
+ "astId": 20,
"contract": "fileA:A",
"label": "s",
"offset": 0,
"slot": "2",
- "type": "t_struct(S)12_storage"
+ "type": "t_struct(S)13_storage"
},
{
- "astId": 20,
+ "astId": 22,
"contract": "fileA:A",
"label": "addr",
"offset": 0,
@@ -275,7 +275,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_address"
},
{
- "astId": 26,
+ "astId": 28,
"contract": "fileA:A",
"label": "map",
"offset": 0,
@@ -283,7 +283,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_mapping(t_uint256,t_mapping(t_address,t_bool))"
},
{
- "astId": 29,
+ "astId": 31,
"contract": "fileA:A",
"label": "array",
"offset": 0,
@@ -291,7 +291,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_array(t_uint256)dyn_storage"
},
{
- "astId": 31,
+ "astId": 33,
"contract": "fileA:A",
"label": "s1",
"offset": 0,
@@ -299,7 +299,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_string_storage"
},
{
- "astId": 33,
+ "astId": 35,
"contract": "fileA:A",
"label": "b1",
"offset": 0,
@@ -354,12 +354,12 @@ value and reference types, types that are encoded packed, and nested types.
"label": "string",
"numberOfBytes": "32"
},
- "t_struct(S)12_storage": {
+ "t_struct(S)13_storage": {
"encoding": "inplace",
"label": "struct A.S",
"members": [
{
- "astId": 2,
+ "astId": 3,
"contract": "fileA:A",
"label": "a",
"offset": 0,
@@ -367,7 +367,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_uint128"
},
{
- "astId": 4,
+ "astId": 5,
"contract": "fileA:A",
"label": "b",
"offset": 16,
@@ -375,7 +375,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_uint128"
},
{
- "astId": 8,
+ "astId": 9,
"contract": "fileA:A",
"label": "staticArray",
"offset": 0,
@@ -383,7 +383,7 @@ value and reference types, types that are encoded packed, and nested types.
"type": "t_array(t_uint256)2_storage"
},
{
- "astId": 11,
+ "astId": 12,
"contract": "fileA:A",
"label": "dynArray",
"offset": 0,
diff --git a/docs/internals/optimiser.rst b/docs/internals/optimiser.rst
deleted file mode 100644
index edf5c4c70..000000000
--- a/docs/internals/optimiser.rst
+++ /dev/null
@@ -1,141 +0,0 @@
-.. index:: optimizer, common subexpression elimination, constant propagation
-
-*************
-The Optimiser
-*************
-
-This section discusses the optimiser that was first added to Solidity,
-which operates on opcode streams. For information on the new Yul-based optimiser,
-please see the `readme on github `_.
-
-The Solidity optimiser operates on assembly. 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.
-
-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 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. Thus code like
-
-::
-
- uint x = 7;
- data[7] = 9;
- if (data[x] != x + 2)
- return 2;
- else
- return 1;
-
-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;
-
-Simple Inlining
----------------
-
-Since Solidity version 0.8.2, there is another optimizer step that replaces certain
-jumps to blocks containing "simple" instructions ending with a "jump" by a copy of these instructions.
-This corresponds to inlining of simple, small Solidity or Yul functions. In particular, the sequence
-``PUSHTAG(tag) JUMP`` may be replaced, whenever the ``JUMP`` is marked as jump "into" a
-function and behind ``tag`` there is a basic block (as described above for the
-"CommonSubexpressionEliminator") that ends in another ``JUMP`` which is marked as a jump
-"out of" a function.
-In particular, consider the following prototypical example of assembly generated for a
-call to an internal Solidity function:
-
-.. code-block:: text
-
- tag_return
- tag_f
- jump // in
- tag_return:
- ...opcodes after call to f...
-
- tag_f:
- ...body of function f...
- jump // out
-
-As long as the body of the function is a continuous basic block, the "Inliner" can replace ``tag_f jump`` by
-the block at ``tag_f`` resulting in:
-
-.. code-block:: text
-
- tag_return
- ...body of function f...
- jump
- tag_return:
- ...opcodes after call to f...
-
- tag_f:
- ...body of function f...
- jump // out
-
-Now ideally, the other optimiser steps described above will result in the return tag push being moved
-towards the remaining jump resulting in:
-
-.. code-block:: text
-
- ...body of function f...
- tag_return
- jump
- tag_return:
- ...opcodes after call to f...
-
- tag_f:
- ...body of function f...
- jump // out
-
-In this situation the "PeepholeOptimizer" will remove the return jump. Ideally, all of this can be done
-for all references to ``tag_f`` leaving it unused, s.t. it can be removed, yielding:
-
-.. code-block:: text
-
- ...body of function f...
- ...opcodes after call to f...
-
-So the call to function ``f`` is inlined and the original definition of ``f`` can be removed.
-
-Inlining like this is attempted, whenever a heuristics suggests that inlining is cheaper over the lifetime of a
-contract than not inlining. This heuristics depends on the size of the function body, the
-number of other references to its tag (approximating the number of calls to the function) and
-the expected number of executions of the contract (the global optimiser parameter "runs").
diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst
new file mode 100644
index 000000000..c1107d1b4
--- /dev/null
+++ b/docs/internals/optimizer.rst
@@ -0,0 +1,1306 @@
+.. index:: optimizer, optimiser, common subexpression elimination, constant propagation
+.. _optimizer:
+
+*************
+The Optimizer
+*************
+
+The Solidity compiler uses two different optimizer modules: The "old" optimizer
+that operates at the opcode level and the "new" optimizer that operates on Yul IR code.
+
+The opcode-based optimizer applies a set of `simplification rules `_
+to opcodes. It also combines equal code sets and removes unused code.
+
+The Yul-based optimizer is much more powerful, because it can work across function
+calls. For example, arbitrary jumps are not possible in Yul, so it is
+possible to compute the side-effects of each function. Consider two function calls,
+where the first does not modify storage and the second does modify storage.
+If their arguments and return values do not depend on each other, we can reorder
+the function calls. Similarly, if a function is
+side-effect free and its result is multiplied by zero, you can remove the function
+call completely.
+
+Currently, the parameter ``--optimize`` activates the opcode-based optimizer for the
+generated bytecode and the Yul optimizer for the Yul code generated internally, for example for ABI coder v2.
+One can use ``solc --ir-optimized --optimize`` to produce an
+optimized experimental Yul IR for a Solidity source. Similarly, one can use ``solc --strict-assembly --optimize``
+for a stand-alone Yul mode.
+
+You can find more details on both optimizer modules and their optimization steps below.
+
+Benefits of Optimizing Solidity Code
+====================================
+
+Overall, the optimizer tries to simplify complicated expressions, which reduces both code
+size and execution cost, i.e., it can reduce gas needed for contract deployment as well as for external calls made to the contract.
+It also specializes or inlines functions. Especially
+function inlining is an operation that can cause much bigger code, but it is
+often done because it results in opportunities for more simplifications.
+
+
+Differences between Optimized and Non-Optimized Code
+====================================================
+
+Generally, the most visible difference is that constant expressions are evaluated at compile time.
+When it comes to the ASM output, one can also notice a reduction of equivalent or duplicate
+code blocks (compare the output of the flags ``--asm`` and ``--asm --optimize``). However,
+when it comes to the Yul/intermediate-representation, there can be significant
+differences, for example, functions may be inlined, combined, or rewritten to eliminate
+redundancies, etc. (compare the output between the flags ``--ir`` and
+``--optimize --ir-optimized``).
+
+Optimizer Parameter Runs
+========================
+
+The number of runs (``--optimize-runs``) specifies roughly how often each opcode of the
+deployed code will be executed across the life-time of the contract. This means it is a
+trade-off parameter between code size (deploy cost) and code execution cost (cost after deployment).
+A "runs" parameter of "1" will produce short but expensive code. In contrast, a larger "runs"
+parameter will produce longer but more gas efficient code. The maximum value of the parameter
+is ``2**32-1``.
+
+.. note::
+
+ A common misconception is that this parameter specifies the number of iterations of the optimizer.
+ This is not true: The optimizer will always run as many times as it can still improve the code.
+
+Opcode-Based Optimizer Module
+=============================
+
+The opcode-based optimizer module operates on assembly code. It splits the
+sequence of instructions into basic blocks at ``JUMPs`` and ``JUMPDESTs``.
+Inside these blocks, the optimizer analyzes 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.
+
+Additionally, the opcode-based optimizer
+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. It first tries to find each new
+expression in a list of already known expressions. If no such matches are found,
+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 which we know always evaluates to one.
+
+Certain optimizer steps symbolically track the storage and memory locations. For example, this
+information is used to compute Keccak-256 hashes that can be evaluated during compile time. Consider
+the sequence:
+
+.. code-block:: none
+
+ PUSH 32
+ PUSH 0
+ CALLDATALOAD
+ PUSH 100
+ DUP2
+ MSTORE
+ KECCAK256
+
+or the equivalent Yul
+
+.. code-block:: yul
+
+ let x := calldataload(0)
+ mstore(x, 100)
+ let value := keccak256(x, 32)
+
+In this case, the optimizer tracks the value at a memory location ``calldataload(0)`` and then
+realizes that the Keccak-256 hash can be evaluated at compile time. This only works if there is no
+other instruction that modifies memory between the ``mstore`` and ``keccak256``. So if there is an
+instruction that writes to memory (or storage), then we need to erase the knowledge of the current
+memory (or storage). There is, however, an exception to this erasing, when we can easily see that
+the instruction doesn't write to a certain location.
+
+For example,
+
+.. code-block:: yul
+
+ let x := calldataload(0)
+ mstore(x, 100)
+ // Current knowledge memory location x -> 100
+ let y := add(x, 32)
+ // Does not clear the knowledge that x -> 100, since y does not write to [x, x + 32)
+ mstore(y, 200)
+ // This Keccak-256 can now be evaluated
+ let value := keccak256(x, 32)
+
+Therefore, modifications to storage and memory locations, of say location ``l``, must erase
+knowledge about storage or memory locations which may be equal to ``l``. More specifically, for
+storage, the optimizer has to erase all knowledge of symbolic locations, that may be equal to ``l``
+and for memory, the optimizer has to erase all knowledge of symbolic locations that may not be at
+least 32 bytes away. If ``m`` denotes an arbitrary location, then this decision on erasure is done
+by computing the value ``sub(l, m)``. For storage, if this value evaluates to a literal that is
+non-zero, then the knowledge about ``m`` will be kept. For memory, if the value evaluates to a
+literal that is between ``32`` and ``2**256 - 32``, then the knowledge about ``m`` will be kept. In
+all other cases, the knowledge about ``m`` will be erased.
+
+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 opcode-based
+optimizer module 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 re-generated. The optimizer 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 based on the value of the constant. Thus code like
+
+.. code-block:: solidity
+
+ uint x = 7;
+ data[7] = 9;
+ if (data[x] != x + 2) // this condition is never true
+ return 2;
+ else
+ return 1;
+
+simplifies to this:
+
+.. code-block:: solidity
+
+ data[7] = 9;
+ return 1;
+
+Simple Inlining
+---------------
+
+Since Solidity version 0.8.2, there is another optimizer step that replaces certain
+jumps to blocks containing "simple" instructions ending with a "jump" by a copy of these instructions.
+This corresponds to inlining of simple, small Solidity or Yul functions. In particular, the sequence
+``PUSHTAG(tag) JUMP`` may be replaced, whenever the ``JUMP`` is marked as jump "into" a
+function and behind ``tag`` there is a basic block (as described above for the
+"CommonSubexpressionEliminator") that ends in another ``JUMP`` which is marked as a jump
+"out of" a function.
+
+In particular, consider the following prototypical example of assembly generated for a
+call to an internal Solidity function:
+
+.. code-block:: text
+
+ tag_return
+ tag_f
+ jump // in
+ tag_return:
+ ...opcodes after call to f...
+
+ tag_f:
+ ...body of function f...
+ jump // out
+
+As long as the body of the function is a continuous basic block, the "Inliner" can replace ``tag_f jump`` by
+the block at ``tag_f`` resulting in:
+
+.. code-block:: text
+
+ tag_return
+ ...body of function f...
+ jump
+ tag_return:
+ ...opcodes after call to f...
+
+ tag_f:
+ ...body of function f...
+ jump // out
+
+Now ideally, the other optimizer steps described above will result in the return tag push being moved
+towards the remaining jump resulting in:
+
+.. code-block:: text
+
+ ...body of function f...
+ tag_return
+ jump
+ tag_return:
+ ...opcodes after call to f...
+
+ tag_f:
+ ...body of function f...
+ jump // out
+
+In this situation the "PeepholeOptimizer" will remove the return jump. Ideally, all of this can be done
+for all references to ``tag_f`` leaving it unused, s.t. it can be removed, yielding:
+
+.. code-block:: text
+
+ ...body of function f...
+ ...opcodes after call to f...
+
+So the call to function ``f`` is inlined and the original definition of ``f`` can be removed.
+
+Inlining like this is attempted, whenever a heuristics suggests that inlining is cheaper over the lifetime of a
+contract than not inlining. This heuristics depends on the size of the function body, the
+number of other references to its tag (approximating the number of calls to the function) and
+the expected number of executions of the contract (the global optimizer parameter "runs").
+
+
+Yul-Based Optimizer Module
+==========================
+
+The Yul-based optimizer consists of several stages and components that all transform
+the AST in a semantically equivalent way. The goal is to end up either with code
+that is shorter or at least only marginally longer but will allow further
+optimization steps.
+
+.. warning::
+
+ Since the optimizer is under heavy development, the information here might be outdated.
+ If you rely on a certain functionality, please reach out to the team directly.
+
+The optimizer currently follows a purely greedy strategy and does not do any
+backtracking.
+
+All components of the Yul-based optimizer module are explained below.
+The following transformation steps are the main components:
+
+ - SSA Transform
+ - Common Subexpression Eliminator
+ - Expression Simplifier
+ - Redundant Assign Eliminator
+ - Full Function Inliner
+
+Optimizer Steps
+---------------
+
+This is a list of all steps the Yul-based optimizer sorted alphabetically. You can find more information
+on the individual steps and their sequence below.
+
+ - :ref:`block-flattener`.
+ - :ref:`circular-reference-pruner`.
+ - :ref:`common-subexpression-eliminator`.
+ - :ref:`conditional-simplifier`.
+ - :ref:`conditional-unsimplifier`.
+ - :ref:`control-flow-simplifier`.
+ - :ref:`dead-code-eliminator`.
+ - :ref:`equivalent-function-combiner`.
+ - :ref:`expression-joiner`.
+ - :ref:`expression-simplifier`.
+ - :ref:`expression-splitter`.
+ - :ref:`for-loop-condition-into-body`.
+ - :ref:`for-loop-condition-out-of-body`.
+ - :ref:`for-loop-init-rewriter`.
+ - :ref:`functional-inliner`.
+ - :ref:`function-grouper`.
+ - :ref:`function-hoister`.
+ - :ref:`function-specializer`.
+ - :ref:`literal-rematerialiser`.
+ - :ref:`load-resolver`.
+ - :ref:`loop-invariant-code-motion`.
+ - :ref:`redundant-assign-eliminator`.
+ - :ref:`reasoning-based-simplifier`.
+ - :ref:`rematerialiser`.
+ - :ref:`SSA-reverser`.
+ - :ref:`SSA-transform`.
+ - :ref:`structural-simplifier`.
+ - :ref:`unused-function-parameter-pruner`.
+ - :ref:`unused-pruner`.
+ - :ref:`var-decl-initializer`.
+
+Selecting Optimizations
+-----------------------
+
+By default the optimizer applies its predefined sequence of optimization steps to
+the generated assembly. You can override this sequence and supply your own using
+the ``--yul-optimizations`` option:
+
+.. code-block:: text
+
+ bash
+ solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul'
+
+The sequence inside ``[...]`` will be applied multiple times in a loop until the Yul code
+remains unchanged or until the maximum number of rounds (currently 12) has been reached.
+
+Available abbreviations are listed in the `Yul optimizer docs `_.
+
+Preprocessing
+-------------
+
+The preprocessing components perform transformations to get the program
+into a certain normal form that is easier to work with. This normal
+form is kept during the rest of the optimization process.
+
+.. _disambiguator:
+
+Disambiguator
+^^^^^^^^^^^^^
+
+The disambiguator takes an AST and returns a fresh copy where all identifiers have
+unique names in the input AST. This is a prerequisite for all other optimizer stages.
+One of the benefits is that identifier lookup does not need to take scopes into account
+which simplifies the analysis needed for other steps.
+
+All subsequent stages have the property that all names stay unique. This means if
+a new identifier needs to be introduced, a new unique name is generated.
+
+.. _function-hoister:
+
+FunctionHoister
+^^^^^^^^^^^^^^^
+
+The function hoister moves all function definitions to the end of the topmost block. This is
+a semantically equivalent transformation as long as it is performed after the
+disambiguation stage. The reason is that moving a definition to a higher-level block cannot decrease
+its visibility and it is impossible to reference variables defined in a different function.
+
+The benefit of this stage is that function definitions can be looked up more easily
+and functions can be optimized in isolation without having to traverse the AST completely.
+
+.. _function-grouper:
+
+FunctionGrouper
+^^^^^^^^^^^^^^^
+
+The function grouper has to be applied after the disambiguator and the function hoister.
+Its effect is that all topmost elements that are not function definitions are moved
+into a single block which is the first statement of the root block.
+
+After this step, a program has the following normal form:
+
+.. code-block:: text
+
+ { I F... }
+
+Where ``I`` is a (potentially empty) block that does not contain any function definitions (not even recursively)
+and ``F`` is a list of function definitions such that no function contains a function definition.
+
+The benefit of this stage is that we always know where the list of function begins.
+
+.. _for-loop-condition-into-body:
+
+ForLoopConditionIntoBody
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This transformation moves the loop-iteration condition of a for-loop into loop body.
+We need this transformation because :ref:`expression-splitter` will not
+apply to iteration condition expressions (the ``C`` in the following example).
+
+.. code-block:: text
+
+ for { Init... } C { Post... } {
+ Body...
+ }
+
+is transformed to
+
+.. code-block:: text
+
+ for { Init... } 1 { Post... } {
+ if iszero(C) { break }
+ Body...
+ }
+
+This transformation can also be useful when paired with ``LoopInvariantCodeMotion``, since
+invariants in the loop-invariant conditions can then be taken outside the loop.
+
+.. _for-loop-init-rewriter:
+
+ForLoopInitRewriter
+^^^^^^^^^^^^^^^^^^^
+
+This transformation moves the initialization part of a for-loop to before
+the loop:
+
+.. code-block:: text
+
+ for { Init... } C { Post... } {
+ Body...
+ }
+
+is transformed to
+
+.. code-block:: text
+
+ {
+ Init...
+ for {} C { Post... } {
+ Body...
+ }
+ }
+
+This eases the rest of the optimization process because we can ignore
+the complicated scoping rules of the for loop initialisation block.
+
+.. _var-decl-initializer:
+
+VarDeclInitializer
+^^^^^^^^^^^^^^^^^^
+This step rewrites variable declarations so that all of them are initialized.
+Declarations like ``let x, y`` are split into multiple declaration statements.
+
+Only supports initializing with the zero literal for now.
+
+Pseudo-SSA Transformation
+-------------------------
+
+The purpose of this components is to get the program into a longer form,
+so that other components can more easily work with it. The final representation
+will be similar to a static-single-assignment (SSA) form, with the difference
+that it does not make use of explicit "phi" functions which combines the values
+from different branches of control flow because such a feature does not exist
+in the Yul language. Instead, when control flow merges, if a variable is re-assigned
+in one of the branches, a new SSA variable is declared to hold its current value,
+so that the following expressions still only need to reference SSA variables.
+
+An example transformation is the following:
+
+.. code-block:: yul
+
+ {
+ let a := calldataload(0)
+ let b := calldataload(0x20)
+ if gt(a, 0) {
+ b := mul(b, 0x20)
+ }
+ a := add(a, 1)
+ sstore(a, add(b, 0x20))
+ }
+
+
+When all the following transformation steps are applied, the program will look
+as follows:
+
+.. code-block:: yul
+
+ {
+ let _1 := 0
+ let a_9 := calldataload(_1)
+ let a := a_9
+ let _2 := 0x20
+ let b_10 := calldataload(_2)
+ let b := b_10
+ let _3 := 0
+ let _4 := gt(a_9, _3)
+ if _4
+ {
+ let _5 := 0x20
+ let b_11 := mul(b_10, _5)
+ b := b_11
+ }
+ let b_12 := b
+ let _6 := 1
+ let a_13 := add(a_9, _6)
+ let _7 := 0x20
+ let _8 := add(b_12, _7)
+ sstore(a_13, _8)
+ }
+
+Note that the only variable that is re-assigned in this snippet is ``b``.
+This re-assignment cannot be avoided because ``b`` has different values
+depending on the control flow. All other variables never change their
+value once they are defined. The advantage of this property is that
+variables can be freely moved around and references to them
+can be exchanged by their initial value (and vice-versa),
+as long as these values are still valid in the new context.
+
+Of course, the code here is far from being optimized. To the contrary, it is much
+longer. The hope is that this code will be easier to work with and furthermore,
+there are optimizer steps that undo these changes and make the code more
+compact again at the end.
+
+.. _expression-splitter:
+
+ExpressionSplitter
+^^^^^^^^^^^^^^^^^^
+
+The expression splitter turns expressions like ``add(mload(x), mul(mload(y), 0x20))``
+into a sequence of declarations of unique variables that are assigned sub-expressions
+of that expression so that each function call has only variables or literals
+as arguments.
+
+The above would be transformed into
+
+.. code-block:: yul
+
+ {
+ let _1 := mload(y)
+ let _2 := mul(_1, 0x20)
+ let _3 := mload(x)
+ let z := add(_3, _2)
+ }
+
+Note that this transformation does not change the order of opcodes or function calls.
+
+It is not applied to loop iteration-condition, because the loop control flow does not allow
+this "outlining" of the inner expressions in all cases. We can sidestep this limitation by applying
+:ref:`for-loop-condition-into-body` to move the iteration condition into loop body.
+
+The final program should be in a form such that (with the exception of loop conditions)
+function calls cannot appear nested inside expressions
+and all function call arguments have to be literals or variables.
+
+The benefits of this form are that it is much easier to re-order the sequence of opcodes
+and it is also easier to perform function call inlining. Furthermore, it is simpler
+to replace individual parts of expressions or re-organize the "expression tree".
+The drawback is that such code is much harder to read for humans.
+
+.. _SSA-transform:
+
+SSATransform
+^^^^^^^^^^^^
+
+This stage tries to replace repeated assignments to
+existing variables by declarations of new variables as much as
+possible.
+The reassignments are still there, but all references to the
+reassigned variables are replaced by the newly declared variables.
+
+Example:
+
+.. code-block:: yul
+
+ {
+ let a := 1
+ mstore(a, 2)
+ a := 3
+ }
+
+is transformed to
+
+.. code-block:: yul
+
+ {
+ let a_1 := 1
+ let a := a_1
+ mstore(a_1, 2)
+ let a_3 := 3
+ a := a_3
+ }
+
+Exact semantics:
+
+For any variable ``a`` that is assigned to somewhere in the code
+(variables that are declared with value and never re-assigned
+are not modified) perform the following transforms:
+
+ - replace ``let a := v`` by ``let a_i := v let a := a_i``
+ - replace ``a := v`` by ``let a_i := v a := a_i`` where ``i`` is a number such that ``a_i`` is yet unused.
+
+Furthermore, always record the current value of ``i`` used for ``a`` and replace each
+reference to ``a`` by ``a_i``.
+The current value mapping is cleared for a variable ``a`` at the end of each block
+in which it was assigned to and at the end of the for loop init block if it is assigned
+inside the for loop body or post block.
+If a variable's value is cleared according to the rule above and the variable is declared outside
+the block, a new SSA variable will be created at the location where control flow joins,
+this includes the beginning of loop post/body block and the location right after
+If/Switch/ForLoop/Block statement.
+
+After this stage, the Redundant Assign Eliminator is recommended to remove the unnecessary
+intermediate assignments.
+
+This stage provides best results if the Expression Splitter and the Common Subexpression Eliminator
+are run right before it, because then it does not generate excessive amounts of variables.
+On the other hand, the Common Subexpression Eliminator could be more efficient if run after the
+SSA transform.
+
+.. _redundant-assign-eliminator:
+
+RedundantAssignEliminator
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The SSA transform always generates an assignment of the form ``a := a_i``, even though
+these might be unnecessary in many cases, like the following example:
+
+.. code-block:: yul
+
+ {
+ let a := 1
+ a := mload(a)
+ a := sload(a)
+ sstore(a, 1)
+ }
+
+The SSA transform converts this snippet to the following:
+
+.. code-block:: yul
+
+ {
+ let a_1 := 1
+ a := a_1
+ let a_2 := mload(a_1)
+ a := a_2
+ let a_3 := sload(a_2)
+ a := a_3
+ sstore(a_3, 1)
+ }
+
+The Redundant Assign Eliminator removes all the three assignments to ``a``, because
+the value of ``a`` is not used and thus turn this
+snippet into strict SSA form:
+
+.. code-block:: yul
+
+ {
+ let a_1 := 1
+ let a_2 := mload(a_1)
+ let a_3 := sload(a_2)
+ sstore(a_3, 1)
+ }
+
+Of course the intricate parts of determining whether an assignment is redundant or not
+are connected to joining control flow.
+
+The component works as follows in detail:
+
+The AST is traversed twice: in an information gathering step and in the
+actual removal step. During information gathering, we maintain a
+mapping from assignment statements to the three states
+"unused", "undecided" and "used" which signifies whether the assigned
+value will be used later by a reference to the variable.
+
+When an assignment is visited, it is added to the mapping in the "undecided" state
+(see remark about for loops below) and every other assignment to the same variable
+that is still in the "undecided" state is changed to "unused".
+When a variable is referenced, the state of any assignment to that variable still
+in the "undecided" state is changed to "used".
+
+At points where control flow splits, a copy
+of the mapping is handed over to each branch. At points where control flow
+joins, the two mappings coming from the two branches are combined in the following way:
+Statements that are only in one mapping or have the same state are used unchanged.
+Conflicting values are resolved in the following way:
+
+ - "unused", "undecided" -> "undecided"
+ - "unused", "used" -> "used"
+ - "undecided, "used" -> "used"
+
+For for-loops, the condition, body and post-part are visited twice, taking
+the joining control-flow at the condition into account.
+In other words, we create three control flow paths: Zero runs of the loop,
+one run and two runs and then combine them at the end.
+
+Simulating a third run or even more is unnecessary, which can be seen as follows:
+
+A state of an assignment at the beginning of the iteration will deterministically
+result in a state of that assignment at the end of the iteration. Let this
+state mapping function be called ``f``. The combination of the three different
+states ``unused``, ``undecided`` and ``used`` as explained above is the ``max``
+operation where ``unused = 0``, ``undecided = 1`` and ``used = 2``.
+
+The proper way would be to compute
+
+::
+
+ max(s, f(s), f(f(s)), f(f(f(s))), ...)
+
+as state after the loop. Since ``f`` just has a range of three different values,
+iterating it has to reach a cycle after at most three iterations,
+and thus ``f(f(f(s)))`` has to equal one of ``s``, ``f(s)``, or ``f(f(s))``
+and thus
+
+::
+
+ max(s, f(s), f(f(s))) = max(s, f(s), f(f(s)), f(f(f(s))), ...).
+
+In summary, running the loop at most twice is enough because there are only three
+different states.
+
+For switch statements that have a "default"-case, there is no control-flow
+part that skips the switch.
+
+When a variable goes out of scope, all statements still in the "undecided"
+state are changed to "unused", unless the variable is the return
+parameter of a function - there, the state changes to "used".
+
+In the second traversal, all assignments that are in the "unused" state are removed.
+
+This step is usually run right after the SSA transform to complete
+the generation of the pseudo-SSA.
+
+Tools
+-----
+
+Movability
+^^^^^^^^^^
+
+Movability is a property of an expression. It roughly means that the expression
+is side-effect free and its evaluation only depends on the values of variables
+and the call-constant state of the environment. Most expressions are movable.
+The following parts make an expression non-movable:
+
+ - function calls (might be relaxed in the future if all statements in the function are movable)
+ - opcodes that (can) have side-effects (like ``call`` or ``selfdestruct``)
+ - opcodes that read or write memory, storage or external state information
+ - opcodes that depend on the current PC, memory size or returndata size
+
+DataflowAnalyzer
+^^^^^^^^^^^^^^^^
+
+The Dataflow Analyzer is not an optimizer step itself but is used as a tool
+by other components. While traversing the AST, it tracks the current value of
+each variable, as long as that value is a movable expression.
+It records the variables that are part of the expression
+that is currently assigned to each other variable. Upon each assignment to
+a variable ``a``, the current stored value of ``a`` is updated and
+all stored values of all variables ``b`` are cleared whenever ``a`` is part
+of the currently stored expression for ``b``.
+
+At control-flow joins, knowledge about variables is cleared if they have or would be assigned
+in any of the control-flow paths. For instance, upon entering a
+for loop, all variables are cleared that will be assigned during the
+body or the post block.
+
+Expression-Scale Simplifications
+--------------------------------
+
+These simplification passes change expressions and replace them by equivalent
+and hopefully simpler expressions.
+
+.. _common-subexpression-eliminator:
+
+CommonSubexpressionEliminator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This step uses the Dataflow Analyzer and replaces subexpressions that
+syntactically match the current value of a variable by a reference to
+that variable. This is an equivalence transform because such subexpressions have
+to be movable.
+
+All subexpressions that are identifiers themselves are replaced by their
+current value if the value is an identifier.
+
+The combination of the two rules above allow to compute a local value
+numbering, which means that if two variables have the same
+value, one of them will always be unused. The Unused Pruner or the
+Redundant Assign Eliminator will then be able to fully eliminate such
+variables.
+
+This step is especially efficient if the expression splitter is run
+before. If the code is in pseudo-SSA form,
+the values of variables are available for a longer time and thus we
+have a higher chance of expressions to be replaceable.
+
+The expression simplifier will be able to perform better replacements
+if the common subexpression eliminator was run right before it.
+
+.. _expression-simplifier:
+
+Expression Simplifier
+^^^^^^^^^^^^^^^^^^^^^
+
+The Expression Simplifier uses the Dataflow Analyzer and makes use
+of a list of equivalence transforms on expressions like ``X + 0 -> X``
+to simplify the code.
+
+It tries to match patterns like ``X + 0`` on each subexpression.
+During the matching procedure, it resolves variables to their currently
+assigned expressions to be able to match more deeply nested patterns
+even when the code is in pseudo-SSA form.
+
+Some of the patterns like ``X - X -> 0`` can only be applied as long
+as the expression ``X`` is movable, because otherwise it would remove its potential side-effects.
+Since variable references are always movable, even if their current
+value might not be, the Expression Simplifier is again more powerful
+in split or pseudo-SSA form.
+
+.. _literal-rematerialiser:
+
+LiteralRematerialiser
+^^^^^^^^^^^^^^^^^^^^^
+
+To be documented.
+
+.. _load-resolver:
+
+LoadResolver
+^^^^^^^^^^^^
+
+Optimisation stage that replaces expressions of type ``sload(x)`` and ``mload(x)`` by the value
+currently stored in storage resp. memory, if known.
+
+Works best if the code is in SSA form.
+
+Prerequisite: Disambiguator, ForLoopInitRewriter.
+
+.. _reasoning-based-simplifier:
+
+ReasoningBasedSimplifier
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This optimizer uses SMT solvers to check whether ``if`` conditions are constant.
+
+ - If ``constraints AND condition`` is UNSAT, the condition is never true and the whole body can be removed.
+ - If ``constraints AND NOT condition`` is UNSAT, the condition is always true and can be replaced by ``1``.
+
+The simplifications above can only be applied if the condition is movable.
+
+It is only effective on the EVM dialect, but safe to use on other dialects.
+
+Prerequisite: Disambiguator, SSATransform.
+
+Statement-Scale Simplifications
+-------------------------------
+
+.. _circular-reference-pruner:
+
+CircularReferencesPruner
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This stage removes functions that call each other but are
+neither externally referenced nor referenced from the outermost context.
+
+.. _conditional-simplifier:
+
+ConditionalSimplifier
+^^^^^^^^^^^^^^^^^^^^^
+
+The Conditional Simplifier inserts assignments to condition variables if the value can be determined
+from the control-flow.
+
+Destroys SSA form.
+
+Currently, this tool is very limited, mostly because we do not yet have support
+for boolean types. Since conditions only check for expressions being nonzero,
+we cannot assign a specific value.
+
+Current features:
+
+ - switch cases: insert " := "
+ - after if statement with terminating control-flow, insert " := 0"
+
+Future features:
+
+ - allow replacements by "1"
+ - take termination of user-defined functions into account
+
+Works best with SSA form and if dead code removal has run before.
+
+Prerequisite: Disambiguator.
+
+.. _conditional-unsimplifier:
+
+ConditionalUnsimplifier
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Reverse of Conditional Simplifier.
+
+.. _control-flow-simplifier:
+
+ControlFlowSimplifier
+^^^^^^^^^^^^^^^^^^^^^
+
+Simplifies several control-flow structures:
+
+ - replace if with empty body with pop(condition)
+ - remove empty default switch case
+ - remove empty switch case if no default case exists
+ - replace switch with no cases with pop(expression)
+ - turn switch with single case into if
+ - replace switch with only default case with pop(expression) and body
+ - replace switch with const expr with matching case body
+ - replace ``for`` with terminating control flow and without other break/continue by ``if``
+ - remove ``leave`` at the end of a function.
+
+None of these operations depend on the data flow. The StructuralSimplifier
+performs similar tasks that do depend on data flow.
+
+The ControlFlowSimplifier does record the presence or absence of ``break``
+and ``continue`` statements during its traversal.
+
+Prerequisite: Disambiguator, FunctionHoister, ForLoopInitRewriter.
+Important: Introduces EVM opcodes and thus can only be used on EVM code for now.
+
+.. _dead-code-eliminator:
+
+DeadCodeEliminator
+^^^^^^^^^^^^^^^^^^
+
+This optimization stage removes unreachable code.
+
+Unreachable code is any code within a block which is preceded by a
+leave, return, invalid, break, continue, selfdestruct or revert.
+
+Function definitions are retained as they might be called by earlier
+code and thus are considered reachable.
+
+Because variables declared in a for loop's init block have their scope extended to the loop body,
+we require ForLoopInitRewriter to run before this step.
+
+Prerequisite: ForLoopInitRewriter, Function Hoister, Function Grouper
+
+.. _unused-pruner:
+
+UnusedPruner
+^^^^^^^^^^^^
+
+This step removes the definitions of all functions that are never referenced.
+
+It also removes the declaration of variables that are never referenced.
+If the declaration assigns a value that is not movable, the expression is retained,
+but its value is discarded.
+
+All movable expression statements (expressions that are not assigned) are removed.
+
+.. _structural-simplifier:
+
+StructuralSimplifier
+^^^^^^^^^^^^^^^^^^^^
+
+This is a general step that performs various kinds of simplifications on
+a structural level:
+
+ - replace if statement with empty body by ``pop(condition)``
+ - replace if statement with true condition by its body
+ - remove if statement with false condition
+ - turn switch with single case into if
+ - replace switch with only default case by ``pop(expression)`` and body
+ - replace switch with literal expression by matching case body
+ - replace for loop with false condition by its initialization part
+
+This component uses the Dataflow Analyzer.
+
+.. _block-flattener:
+
+BlockFlattener
+^^^^^^^^^^^^^^
+
+This stage eliminates nested blocks by inserting the statement in the
+inner block at the appropriate place in the outer block:
+
+.. code-block:: yul
+
+ {
+ let x := 2
+ {
+ let y := 3
+ mstore(x, y)
+ }
+ }
+
+is transformed to
+
+.. code-block:: yul
+
+ {
+ let x := 2
+ let y := 3
+ mstore(x, y)
+ }
+
+As long as the code is disambiguated, this does not cause a problem because
+the scopes of variables can only grow.
+
+.. _loop-invariant-code-motion:
+
+LoopInvariantCodeMotion
+^^^^^^^^^^^^^^^^^^^^^^^
+This optimization moves movable SSA variable declarations outside the loop.
+
+Only statements at the top level in a loop's body or post block are considered, i.e variable
+declarations inside conditional branches will not be moved out of the loop.
+
+Requirements:
+
+ - The Disambiguator, ForLoopInitRewriter and FunctionHoister must be run upfront.
+ - Expression splitter and SSA transform should be run upfront to obtain better result.
+
+
+Function-Level Optimizations
+----------------------------
+
+.. _function-specializer:
+
+FunctionSpecializer
+^^^^^^^^^^^^^^^^^^^
+
+This step specializes the function with its literal arguments.
+
+If a function, say, ``function f(a, b) { sstore (a, b) }``, is called with literal arguments, for
+example, ``f(x, 5)``, where ``x`` is an identifier, it could be specialized by creating a new
+function ``f_1`` that takes only one argument, i.e.,
+
+.. code-block:: yul
+
+ function f_1(a_1) {
+ let b_1 := 5
+ sstore(a_1, b_1)
+ }
+
+Other optimization steps will be able to make more simplifications to the function. The
+optimization step is mainly useful for functions that would not be inlined.
+
+Prerequisites: Disambiguator, FunctionHoister
+
+LiteralRematerialiser is recommended as a prerequisite, even though it's not required for
+correctness.
+
+.. _unused-function-parameter-pruner:
+
+UnusedFunctionParameterPruner
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This step removes unused parameters in a function.
+
+If a parameter is unused, like ``c`` and ``y`` in, ``function f(a,b,c) -> x, y { x := div(a,b) }``, we
+remove the parameter and create a new "linking" function as follows:
+
+.. code-block:: yul
+
+ function f(a,b) -> x { x := div(a,b) }
+ function f2(a,b,c) -> x, y { x := f(a,b) }
+
+and replace all references to ``f`` by ``f2``.
+The inliner should be run afterwards to make sure that all references to ``f2`` are replaced by
+``f``.
+
+Prerequisites: Disambiguator, FunctionHoister, LiteralRematerialiser.
+
+The step LiteralRematerialiser is not required for correctness. It helps deal with cases such as:
+``function f(x) -> y { revert(y, y} }`` where the literal ``y`` will be replaced by its value ``0``,
+allowing us to rewrite the function.
+
+.. _equivalent-function-combiner:
+
+EquivalentFunctionCombiner
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If two functions are syntactically equivalent, while allowing variable
+renaming but not any re-ordering, then any reference to one of the
+functions is replaced by the other.
+
+The actual removal of the function is performed by the Unused Pruner.
+
+
+Function Inlining
+-----------------
+
+.. _functional-inliner:
+
+FunctionalInliner
+^^^^^^^^^^^^^^^^^
+
+This component of the optimizer performs restricted function inlining by inlining functions that can be
+inlined inside functional expressions, i.e. functions that:
+
+ - return a single value.
+ - have a body like ``r := ``.
+ - neither reference themselves nor ``r`` in the right hand side.
+
+Furthermore, for all parameters, all of the following need to be true:
+
+ - The argument is movable.
+ - The parameter is either referenced less than twice in the function body, or the argument is rather cheap
+ ("cost" of at most 1, like a constant up to 0xff).
+
+Example: The function to be inlined has the form of ``function f(...) -> r { r := E }`` where
+``E`` is an expression that does not reference ``r`` and all arguments in the function call are movable expressions.
+
+The result of this inlining is always a single expression.
+
+This component can only be used on sources with unique names.
+
+.. _full-function-inliner:
+
+FullFunctionInliner
+^^^^^^^^^^^^^^^^^^^
+
+The Full Function Inliner replaces certain calls of certain functions
+by the function's body. This is not very helpful in most cases, because
+it just increases the code size but does not have a benefit. Furthermore,
+code is usually very expensive and we would often rather have shorter
+code than more efficient code. In same cases, though, inlining a function
+can have positive effects on subsequent optimizer steps. This is the case
+if one of the function arguments is a constant, for example.
+
+During inlining, a heuristic is used to tell if the function call
+should be inlined or not.
+The current heuristic does not inline into "large" functions unless
+the called function is tiny. Functions that are only used once
+are inlined, as well as medium-sized functions, while function
+calls with constant arguments allow slightly larger functions.
+
+
+In the future, we may include a backtracking component
+that, instead of inlining a function right away, only specializes it,
+which means that a copy of the function is generated where
+a certain parameter is always replaced by a constant. After that,
+we can run the optimizer on this specialized function. If it
+results in heavy gains, the specialized function is kept,
+otherwise the original function is used instead.
+
+Cleanup
+-------
+
+The cleanup is performed at the end of the optimizer run. It tries
+to combine split expressions into deeply nested ones again and also
+improves the "compilability" for stack machines by eliminating
+variables as much as possible.
+
+.. _expression-joiner:
+
+ExpressionJoiner
+^^^^^^^^^^^^^^^^
+
+This is the opposite operation of the expression splitter. It turns a sequence of
+variable declarations that have exactly one reference into a complex expression.
+This stage fully preserves the order of function calls and opcode executions.
+It does not make use of any information concerning the commutativity of the opcodes;
+if moving the value of a variable to its place of use would change the order
+of any function call or opcode execution, the transformation is not performed.
+
+Note that the component will not move the assigned value of a variable assignment
+or a variable that is referenced more than once.
+
+The snippet ``let x := add(0, 2) let y := mul(x, mload(2))`` is not transformed,
+because it would cause the order of the call to the opcodes ``add`` and
+``mload`` to be swapped - even though this would not make a difference
+because ``add`` is movable.
+
+When reordering opcodes like that, variable references and literals are ignored.
+Because of that, the snippet ``let x := add(0, 2) let y := mul(x, 3)`` is
+transformed to ``let y := mul(add(0, 2), 3)``, even though the ``add`` opcode
+would be executed after the evaluation of the literal ``3``.
+
+.. _SSA-reverser:
+
+SSAReverser
+^^^^^^^^^^^
+
+This is a tiny step that helps in reversing the effects of the SSA transform
+if it is combined with the Common Subexpression Eliminator and the
+Unused Pruner.
+
+The SSA form we generate is detrimental to code generation on the EVM and
+WebAssembly alike because it generates many local variables. It would
+be better to just re-use existing variables with assignments instead of
+fresh variable declarations.
+
+The SSA transform rewrites
+
+.. code-block:: yul
+
+ a := E
+ mstore(a, 1)
+
+to
+
+.. code-block:: yul
+
+ let a_1 := E
+ a := a_1
+ mstore(a_1, 1)
+
+The problem is that instead of ``a``, the variable ``a_1`` is used
+whenever ``a`` was referenced. The SSA transform changes statements
+of this form by just swapping out the declaration and the assignment. The above
+snippet is turned into
+
+.. code-block:: yul
+
+ a := E
+ let a_1 := a
+ mstore(a_1, 1)
+
+This is a very simple equivalence transform, but when we now run the
+Common Subexpression Eliminator, it will replace all occurrences of ``a_1``
+by ``a`` (until ``a`` is re-assigned). The Unused Pruner will then
+eliminate the variable ``a_1`` altogether and thus fully reverse the
+SSA transform.
+
+.. _stack-compressor:
+
+StackCompressor
+^^^^^^^^^^^^^^^
+
+One problem that makes code generation for the Ethereum Virtual Machine
+hard is the fact that there is a hard limit of 16 slots for reaching
+down the expression stack. This more or less translates to a limit
+of 16 local variables. The stack compressor takes Yul code and
+compiles it to EVM bytecode. Whenever the stack difference is too
+large, it records the function this happened in.
+
+For each function that caused such a problem, the Rematerialiser
+is called with a special request to aggressively eliminate specific
+variables sorted by the cost of their values.
+
+On failure, this procedure is repeated multiple times.
+
+.. _rematerialiser:
+
+Rematerialiser
+^^^^^^^^^^^^^^
+
+The rematerialisation stage tries to replace variable references by the expression that
+was last assigned to the variable. This is of course only beneficial if this expression
+is comparatively cheap to evaluate. Furthermore, it is only semantically equivalent if
+the value of the expression did not change between the point of assignment and the
+point of use. The main benefit of this stage is that it can save stack slots if it
+leads to a variable being eliminated completely (see below), but it can also
+save a DUP opcode on the EVM if the expression is very cheap.
+
+The Rematerialiser uses the Dataflow Analyzer to track the current values of variables,
+which are always movable.
+If the value is very cheap or the variable was explicitly requested to be eliminated,
+the variable reference is replaced by its current value.
+
+.. _for-loop-condition-out-of-body:
+
+ForLoopConditionOutOfBody
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Reverses the transformation of ForLoopConditionIntoBody.
+
+For any movable ``c``, it turns
+
+::
+
+ for { ... } 1 { ... } {
+ if iszero(c) { break }
+ ...
+ }
+
+into
+
+::
+
+ for { ... } c { ... } {
+ ...
+ }
+
+and it turns
+
+::
+
+ for { ... } 1 { ... } {
+ if c { break }
+ ...
+ }
+
+into
+
+::
+
+ for { ... } iszero(c) { ... } {
+ ...
+ }
+
+The LiteralRematerialiser should be run before this step.
+
+
+WebAssembly specific
+--------------------
+
+MainFunction
+^^^^^^^^^^^^
+
+Changes the topmost block to be a function with a specific name ("main") which has no
+inputs nor outputs.
+
+Depends on the Function Grouper.
diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst
index ddcc5a83d..6b427226c 100644
--- a/docs/introduction-to-smart-contracts.rst
+++ b/docs/introduction-to-smart-contracts.rst
@@ -15,7 +15,7 @@ everything right now, we will go into more detail later.
Storage Example
===============
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -51,8 +51,10 @@ code that manages the database. In this example, the contract defines the
functions ``set`` and ``get`` that can be used to modify
or retrieve the value of the variable.
-To access a state variable, you do not need the prefix ``this.`` as is common in
-other languages.
+To access a member (like a state variable) of the current contract, you do not typically add the ``this.`` prefix,
+you just access it directly via its name.
+Unlike in some other languages, omitting it is not just a matter of style,
+it results in a completely different way to access the member, but more on this later.
This contract does not do much yet apart from (due to the infrastructure
built by Ethereum) allowing anyone to store a single number that is accessible by
@@ -80,7 +82,7 @@ cryptocurrency. The contract allows only its creator to create new coins (differ
Anyone can send coins to each other without a need for
registering with a username and password, all you need is an Ethereum keypair.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -224,8 +226,8 @@ a failure can more easily be debugged or reacted upon.
The ``send`` function can be used by anyone (who already
has some of these coins) to send coins to anyone else. If the sender does not have
-enough coins to send, the ``require`` call fails and provides the
-sender with an appropriate error message string.
+enough coins to send, the ``if`` condition evaluates to true. As a result, the ``revert`` will cause the operation to fail
+while providing the sender with error details using the ``InsufficientBalance`` error.
.. note::
If you use
diff --git a/docs/ir/ir-breaking-changes.rst b/docs/ir/ir-breaking-changes.rst
index 2d5345080..7d6b6d54f 100644
--- a/docs/ir/ir-breaking-changes.rst
+++ b/docs/ir/ir-breaking-changes.rst
@@ -14,7 +14,8 @@ hiding new and different behavior in existing code.
* When storage structs are deleted, every storage slot that contains a member of the struct is set to zero entirely. Formally, padding space was left untouched.
Consequently, if the padding space within a struct is used to store data (e.g. in the context of a contract upgrade), you have to be aware that ``delete`` will now also clear the added member (while it wouldn't have been cleared in the past).
-::
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0;
@@ -42,7 +43,8 @@ We have the same behavior for implicit delete, for example when array of structs
The new code generator implements modifiers using actual functions and passes function parameters on.
This means that multiple executions of a function will get the same values for the parameters.
-::
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0;
contract C {
@@ -71,7 +73,9 @@ New order:
2. Constructor, if present.
This causes differences in some contracts, for example:
-::
+
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0;
@@ -93,7 +97,9 @@ With the new rules, ``y`` will be set to 42. We first initialize ``x`` to 0, the
* Copying ``bytes`` arrays from memory to storage is implemented in a different way. The old code generator always copies full words, while the new one cuts the byte array after its end. The old behaviour can lead to dirty data being copied after the end of the array (but still in the same storage slot).
This causes differences in some contracts, for example:
-::
+
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.8.0;
@@ -123,7 +129,8 @@ Now it is returning ``0x64656164626565660000000000000000000000000000000000000000
For example:
-::
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.8.0;
contract C {
@@ -138,10 +145,11 @@ The function ``preincr_u8(1)`` returns the following values:
.. index:: ! evaluation order; function arguments
-On the other hand, function argument expressions are evaluated in the same order by both code generators.
+On the other hand, function argument expressions are evaluated in the same order by both code generators with the exception of the global functions ``addmod`` and ``mulmod``.
For example:
-::
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.8.0;
contract C {
@@ -157,6 +165,27 @@ The function ``g(1, 2)`` returns the following values:
- Old code generator: ``10`` (``add(2 + 3, 2 + 3)``) but the return value is unspecified in general
- New code generator: ``10`` but the return value is not guaranteed
+The arguments to the global functions ``addmod`` and ``mulmod`` are evaluated right-to-left by the old code generator
+and left-to-right by the new code generator.
+For example:
+
+::
+ // SPDX-License-Identifier: GPL-3.0
+ pragma solidity >0.8.0;
+ contract C {
+ function f() public pure returns (uint256 aMod, uint256 mMod) {
+ uint256 x = 3;
+ // Old code gen: add/mulmod(5, 4, 3)
+ // New code gen: add/mulmod(4, 5, 5)
+ aMod = addmod(++x, ++x, x);
+ mMod = mulmod(++x, ++x, x);
+ }
+ }
+
+The function ``f()`` returns the following values:
+- Old code generator: ``aMod = 0`` and ``mMod = 2``
+- New code generator: ``aMod = 4`` and ``mMod = 0``
+
Internals
=========
@@ -188,7 +217,9 @@ The old code generator only performs cleanup before an operation whose result co
The new code generator performs cleanup after any operation that can result in dirty bits.
For example:
-::
+
+.. code-block:: solidity
+
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.8.0;
contract C {
diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst
index fb9844c65..22624c410 100644
--- a/docs/layout-of-source-files.rst
+++ b/docs/layout-of-source-files.rst
@@ -163,7 +163,7 @@ The component does not yet support all features of the Solidity language and
likely outputs many warnings. In case it reports unsupported features, the
analysis may not be fully sound.
-.. index:: source file, ! import, module
+.. index:: source file, ! import, module, source unit
.. _import:
@@ -184,6 +184,7 @@ At a global level, you can use import statements of the following form:
import "filename";
+The ``filename`` part is called an *import path*.
This statement imports all global symbols from "filename" (and symbols imported there) into the
current global scope (different than in ES6 but backwards-compatible for Solidity).
This form is not recommended for use, because it unpredictably pollutes the namespace.
@@ -216,101 +217,34 @@ the code below creates new global symbols ``alias`` and ``symbol2`` which refere
import {symbol1 as alias, symbol2} from "filename";
-Paths
------
+.. index:: virtual filesystem, source unit name, import; path, filesystem path, import callback, Remix IDE
-In the above, ``filename`` is always treated as a path with ``/`` as directory separator,
-and ``.`` as the current and ``..`` as the parent directory. When ``.`` or ``..`` is followed by a character except ``/``,
-it is not considered as the current or the parent directory.
-All path names are treated as absolute paths unless they start with the current ``.`` or the parent directory ``..``.
+Import Paths
+------------
-To import a file ``filename`` from the same directory as the current file, use ``import "./filename" as symbolName;``.
-If you use ``import "filename" as symbolName;`` instead, a different file could be referenced
-(in a global "include directory").
+In order to be able to support reproducible builds on all platforms, the Solidity compiler has to
+abstract away the details of the filesystem where source files are stored.
+For this reason import paths do not refer directly to files in the host filesystem.
+Instead the compiler maintains an internal database (*virtual filesystem* or *VFS* for short) where
+each source unit is assigned a unique *source unit name* which is an opaque and unstructured identifier.
+The import path specified in an import statement is translated into a source unit name and used to
+find the corresponding source unit in this database.
-It depends on the compiler (see :ref:`import-compiler`) how to actually resolve the paths.
-In general, the directory hierarchy does not need to strictly map onto your local
-filesystem, and the path can also map to resources such as ipfs, http or git.
+Using the :ref:`Standard JSON ` API it is possible to directly provide the names and
+content of all the source files as a part of the compiler input.
+In this case source unit names are truly arbitrary.
+If, however, you want the compiler to automatically find and load source code into the VFS, your
+source unit names need to be structured in a way that makes it possible for an :ref:`import callback
+` to locate them.
+When using the command-line compiler the default import callback supports only loading source code
+from the host filesystem, which means that your source unit names must be paths.
+Some environments provide custom callbacks that are more versatile.
+For example the `Remix IDE `_ provides one that
+lets you `import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry
+`_.
-.. note::
- Always use relative imports like ``import "./filename.sol";`` and avoid
- using ``..`` in path specifiers. In the latter case, it is probably better to use
- global paths and set up remappings as explained below.
-
-.. _import-compiler:
-
-Use in Actual Compilers
------------------------
-
-When invoking the compiler, you can specify how to discover the first element
-of a path, and also path prefix remappings. For
-example you can setup a remapping so that everything imported from the virtual
-directory ``github.com/ethereum/dapp-bin/library`` would actually be read from
-your local directory ``/usr/local/dapp-bin/library``.
-If multiple remappings apply, the one with the longest key is tried first.
-An empty prefix is not allowed. The remappings can depend on a context,
-which allows you to configure packages to import e.g., different versions of a
-library of the same name.
-
-**solc**:
-
-For solc (the commandline compiler), you provide these path remappings as
-``context:prefix=target`` arguments, where both the ``context:`` and the
-``=target`` parts are optional (``target`` defaults to ``prefix`` in this
-case). All remapping values that are regular files are compiled (including
-their dependencies).
-
-This mechanism is backwards-compatible (as long
-as no filename contains ``=`` or ``:``) and thus not a breaking change. All
-files in or below the ``context`` directory that import a file that starts with
-``prefix`` are redirected by replacing ``prefix`` by ``target``.
-
-For example, if you clone ``github.com/ethereum/dapp-bin/`` locally to
-``/usr/local/dapp-bin``, you can use the following in your source file:
-
-::
-
- import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
-
-Then run the compiler:
-
-.. code-block:: bash
-
- solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol
-
-As a more complex example, suppose you rely on a module that uses an old
-version of dapp-bin that you checked out to ``/usr/local/dapp-bin_old``, then you can run:
-
-.. code-block:: bash
-
- solc module1:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ \
- module2:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin_old/ \
- source.sol
-
-This means that all imports in ``module2`` point to the old version but imports
-in ``module1`` point to the new version.
-
-.. note::
-
- ``solc`` only allows you to include files from certain directories. They have
- to be in the directory (or subdirectory) of one of the explicitly specified
- source files or in the directory (or subdirectory) of a remapping target. If
- you want to allow direct absolute includes, add the remapping ``/=/``.
-
-If there are multiple remappings that lead to a valid file, the remapping
-with the longest common prefix is chosen.
-
-**Remix**:
-
-`Remix `_ provides an automatic remapping for
-GitHub and automatically retrieves the file over the network. You can import
-the iterable mapping as above, e.g.
-
-::
-
- import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;
-
-Remix may add other source code providers in the future.
+For a complete description of the virtual filesystem and the path resolution logic used by the
+compiler see :ref:`Path Resolution `.
.. index:: ! comment, natspec
diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst
index de05f6858..7007fe4a1 100644
--- a/docs/natspec-format.rst
+++ b/docs/natspec-format.rst
@@ -72,7 +72,7 @@ The following example shows a contract and a function using all available tags.
/// @notice Calculate tree age in years, rounded up, for live trees
/// @dev The Alexandr N. Tetearing algorithm could increase precision
/// @param rings The number of rings from dendrochronological sample
- /// @return age in years, rounded up for partial years
+ /// @return Age in years, rounded up for partial years
function age(uint256 rings) external virtual pure returns (uint256) {
return rings + 1;
}
@@ -115,10 +115,10 @@ in the same way as if it were tagged with ``@notice``.
=============== ====================================================================================== =============================
Tag Context
=============== ====================================================================================== =============================
-``@title`` A title that should describe the contract/interface contract, interface
-``@author`` The name of the author contract, interface
-``@notice`` Explain to an end user what this does contract, interface, function, public state variable, event
-``@dev`` Explain to a developer any extra details contract, interface, function, state variable, event
+``@title`` A title that should describe the contract/interface contract, library, interface
+``@author`` The name of the author contract, library, interface
+``@notice`` Explain to an end user what this does contract, library, interface, function, public state variable, event
+``@dev`` Explain to a developer any extra details contract, library, interface, function, state variable, event
``@param`` Documents a parameter just like in Doxygen (must be followed by parameter name) function, event
``@return`` Documents the return variables of a contract's function function, public state variable
``@inheritdoc`` Copies all missing tags from the base function (must be followed by the contract name) function, public state variable
diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst
new file mode 100644
index 000000000..5848e3f9a
--- /dev/null
+++ b/docs/path-resolution.rst
@@ -0,0 +1,486 @@
+.. _path-resolution:
+
+**********************
+Import Path Resolution
+**********************
+
+In order to be able to support reproducible builds on all platforms, the Solidity compiler has to
+abstract away the details of the filesystem where source files are stored.
+Paths used in imports must work the same way everywhere while the command-line interface must be
+able to work with platform-specific paths to provide good user experience.
+This section aims to explain in detail how Solidity reconciles these requirements.
+
+.. index:: ! virtual filesystem, ! VFS, ! source unit name
+.. _virtual-filesystem:
+
+Virtual Filesystem
+==================
+
+The compiler maintains an internal database (*virtual filesystem* or *VFS* for short) where each
+source unit is assigned a unique *source unit name* which is an opaque and unstructured identifier.
+When you use the :ref:`import statement `, you specify an *import path* that references a
+source unit name.
+
+.. index:: ! import callback, ! Host Filesystem Loader
+.. _import-callback:
+
+Import Callback
+---------------
+
+The VFS is initially populated only with files the compiler has received as input.
+Additional files can be loaded during compilation using an *import callback*, which is different
+depending on the type of compiler you use (see below).
+If the compiler does not find any source unit name matching the import path in the VFS, it invokes
+the callback, which is responsible for obtaining the source code to be placed under that name.
+An import callback is free to interpret source unit names in an arbitrary way, not just as paths.
+If there is no callback available when one is needed or if it fails to locate the source code,
+compilation fails.
+
+The command-line compiler provides the *Host Filesystem Loader* - a rudimentary callback
+that interprets a source unit name as a path in the local filesystem.
+The `JavaScript interface `_ does not provide any by default,
+but one can be provided by the user.
+This mechanism can be used to obtain source code from locations other then the local filesystem
+(which may not even be accessible, e.g. when the compiler is running in a browser).
+For example the `Remix IDE `_ provides a versatile callback that
+lets you `import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry
+`_.
+
+.. note::
+
+ Host Filesystem Loader's file lookup is platform-dependent.
+ For example backslashes in a source unit name can be interpreted as directory separators or not
+ and the lookup can be case-sensitive or not, depending on the underlying platform.
+
+ For portability it is recommended to avoid using import paths that will work correctly only
+ with a specific import callback or only on one platform.
+ For example you should always use forward slashes since they work as path separators also on
+ platforms that support backslashes.
+
+Initial Content of the Virtual Filesystem
+-----------------------------------------
+
+The initial content of the VFS depends on how you invoke the compiler:
+
+#. **solc / command-line interface**
+
+ When you compile a file using the command-line interface of the compiler, you provide one or
+ more paths to files containing Solidity code:
+
+ .. code-block:: bash
+
+ solc contract.sol /usr/local/dapp-bin/token.sol
+
+ The source unit name of a file loaded this way is simply the specified path after shell expansion
+ and with platform-specific separators converted to forward slashes.
+
+ .. index:: standard JSON
+
+#. **Standard JSON**
+
+ When using the :ref:`Standard JSON ` API (via either the `JavaScript interface
+ `_ or the ``--standard-json`` command-line option)
+ you provide input in JSON format, containing, among other things, the content of all your source
+ files:
+
+ .. code-block:: json
+
+ {
+ "language": "Solidity",
+ "sources": {
+ "contract.sol": {
+ "content": "import \"./util.sol\";\ncontract C {}"
+ },
+ "util.sol": {
+ "content": "library Util {}"
+ },
+ "/usr/local/dapp-bin/token.sol": {
+ "content": "contract Token {}"
+ }
+ },
+ "settings": {"outputSelection": {"*": { "*": ["metadata", "evm.bytecode"]}}}
+ }
+
+ The ``sources`` dictionary becomes the initial content of the virtual filesystem and its keys
+ are used as source unit names.
+
+ .. _initial-vfs-content-standard-json-with-import-callback:
+
+#. **Standard JSON (via import callback)**
+
+ With Standard JSON it is also possible to tell the compiler to use the import callback to obtain
+ the source code:
+
+ .. code-block:: json
+
+ {
+ "language": "Solidity",
+ "sources": {
+ "/usr/local/dapp-bin/token.sol": {
+ "urls": [
+ "/projects/mytoken.sol",
+ "https://example.com/projects/mytoken.sol"
+ ]
+ }
+ },
+ "settings": {"outputSelection": {"*": { "*": ["metadata", "evm.bytecode"]}}}
+ }
+
+ If an import callback is available, the compiler will give it the strings specified in
+ ``urls`` one by one, until one is loaded successfully or the end of the list is reached.
+
+ The source unit names are determined the same way as when using ``content`` - they are keys of
+ the ``sources`` dictionary and the content of ``urls`` does not affect them in any way.
+
+ .. index:: standard input, stdin,
+
+#. **Standard input**
+
+ On the command line it is also possible to provide the source by sending it to compiler's
+ standard input:
+
+ .. code-block:: bash
+
+ echo 'import "./util.sol"; contract C {}' | solc -
+
+ ``-`` used as one of the arguments instructs the compiler to place the content of the standard
+ input in the virtual filesystem under a special source unit name: ````.
+
+Once the VFS is initialized, additional files can still be added to it only through the import
+callback.
+
+.. index:: ! import; path
+
+Imports
+=======
+
+The import statement specifies an *import path*.
+Based on how the import path is specified, we can divide imports into two categories:
+
+- :ref:`Direct imports `, where you specify the full source unit name directly.
+- :ref:`Relative imports `, where you specify a path starting with ``./`` or ``../``
+ to be combined with the source unit name of the importing file.
+
+
+.. code-block:: solidity
+ :caption: contracts/contract.sol
+
+ import "./math/math.sol";
+ import "contracts/tokens/token.sol";
+
+In the above ``./math/math.sol`` and ``contracts/tokens/token.sol`` are import paths while the
+source unit names they translate to are ``contracts/math/math.sol`` and ``contracts/tokens/token.sol``
+respectively.
+
+.. index:: ! direct import, import; direct
+.. _direct-imports:
+
+Direct Imports
+--------------
+
+An import that does not start with ``./`` or ``../`` is a *direct import*.
+
+::
+
+ import "/project/lib/util.sol"; // source unit name: /project/lib/util.sol
+ import "lib/util.sol"; // source unit name: lib/util.sol
+ import "@openzeppelin/address.sol"; // source unit name: @openzeppelin/address.sol
+ import "https://example.com/token.sol"; // source unit name: https://example.com/token.sol
+
+After applying any :ref:`import remappings ` the import path simply becomes the
+source unit name.
+
+.. note::
+
+ A source unit name is just an identifier and even if its value happens to look like a path, it
+ is not subject to the normalization rules you would typically expect in a shell.
+ Any ``/./`` or ``/../`` seguments or sequences of multiple slashes remain a part of it.
+ When the source is provided via Standard JSON interface it is entirely possible to associate
+ different content with source unit names that would refer to the same file on disk.
+
+When the source is not available in the virtual filesystem, the compiler passes the source unit name
+to the import callback.
+The Host Filesystem Loader will attempt to use it as a path and look up the file on disk.
+At this point the platform-specific normalization rules kick in and names that were considered
+different in the VFS may actually result in the same file being loaded.
+For example ``/project/lib/math.sol`` and ``/project/lib/../lib///math.sol`` are considered
+completely different in the VFS even though they refer to the same file on disk.
+
+.. note::
+
+ Even if an import callback ends up loading source code for two different source unit names from
+ the same file on disk, the compiler will still see them as separate source units.
+ It is the source unit name that matters, not the physical location of the code.
+
+.. index:: ! relative import, ! import; relative
+.. _relative-imports:
+
+Relative Imports
+----------------
+
+An import starting with ``./`` or ``../`` is a *relative import*.
+Such imports specify a path relative to the source unit name of the importing source unit:
+
+.. code-block:: solidity
+ :caption: /project/lib/math.sol
+
+ import "./util.sol" as util; // source unit name: /project/lib/util.sol
+ import "../token.sol" as token; // source unit name: /project/token.sol
+
+.. code-block:: solidity
+ :caption: lib/math.sol
+
+ import "./util.sol" as util; // source unit name: lib/util.sol
+ import "../token.sol" as token; // source unit name: token.sol
+
+.. note::
+
+ Relative imports **always** start with ``./`` or ``../`` so ``import "util.sol"``, unlike
+ ``import "./util.sol"``, is a direct import.
+ While both paths would be considered relative in the host filesystem, ``util.sol`` is actually
+ absolute in the VFS.
+
+Let us define a *path segment* as any non-empty part of the path that does not contain a separator
+and is bounded by two path separators.
+A separator is a forward slash or the beginning/end of the string.
+For example in ``./abc/..//`` there are three path segments: ``.``, ``abc`` and ``..``.
+
+The compiler computes a source unit name from the import path in the following way:
+
+1. First a prefix is computed
+
+ - Prefix is initialized with the source unit name of the importing source unit.
+ - The last path segment with preceding slashes is removed from the prefix.
+ - Then, the leading part of the normalized import path, consisting only of ``/`` and ``.``
+ characters is considered.
+ For every ``..`` segment found in this part the last path segment with preceding slashes is
+ removed from the prefix.
+
+2. Then the prefix is prepended to the normalized import path.
+ If the prefix is non-empty, a single slash is inserted between it and the import path.
+
+The removal of the last path segment with preceding slashes is understood to
+work as follows:
+
+1. Everything past the last slash is removed (i.e. ``a/b//c.sol`` becomes ``a/b//``).
+2. All trailing slashes are removed (i.e. ``a/b//`` becomes ``a/b``).
+
+The normalization rules are the same as for UNIX paths, namely:
+
+- All the internal ``.`` segments are removed.
+- Every internal ``..`` segment backtracks one level up in the hierarchy.
+- Multiple slashes are squashed into a single one.
+
+Note that normalization is performed only on the import path.
+The source unit name of the importing module that is used for the prefix remains unnormalized.
+This ensures that the ``protocol://`` part does not turn into ``protocol:/`` if the importing file
+is identified with a URL.
+
+If your import paths are already normalized, you can expect the above algorithm to produce very
+intuitive results.
+Here are some examples of what you can expect if they are not:
+
+.. code-block:: solidity
+ :caption: lib/src/../contract.sol
+
+ import "./util/./util.sol"; // source unit name: lib/src/../util/util.sol
+ import "./util//util.sol"; // source unit name: lib/src/../util/util.sol
+ import "../util/../array/util.sol"; // source unit name: lib/src/array/util.sol
+ import "../.././../util.sol"; // source unit name: util.sol
+ import "../../.././../util.sol"; // source unit name: util.sol
+
+.. note::
+
+ The use of relative imports containing leading ``..`` segments is not recommended.
+ The same effect can be achieved in a more reliable way by using direct imports with
+ :ref:`base path ` and :ref:`import remapping `.
+
+.. index:: ! base path, --base-path
+.. _base-path:
+
+Base Path
+=========
+
+The base path specifies the directory that the Host Filesystem Loader will load files from.
+It is simply prepended to a source unit name before the filesystem lookup is performed.
+
+By default the base path is empty, which leaves the source unit name unchanged.
+When the source unit name is a relative path, this results in the file being looked up in the
+directory the compiler has been invoked from.
+It is also the only value that results in absolute paths in source unit names being actually
+interpreted as absolute paths on disk.
+
+If the base path itself is relative, it is also interpreted as relative to the current working
+directory of the compiler.
+
+.. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target
+.. _import-remapping:
+
+Import Remapping
+================
+
+Import remapping allows you to redirect imports to a different location in the virtual filesystem.
+The mechanism works by changing the translation between import paths and source unit names.
+For example you can set up a remapping so that any import from the virtual directory
+``github.com/ethereum/dapp-bin/library/`` would be seen as an import from ``dapp-bin/library/`` instead.
+
+You can limit the scope of a remapping by specifying a *context*.
+This allows creating remappings that apply only to imports located in a specific library or a specific file.
+Without a context a remapping is applied to every matching import in all the files in the virtual
+filesystem.
+
+Import remappings have the form of ``context:prefix=target``:
+
+- ``context`` must match the beginning of the source unit name of the file containing the import.
+- ``prefix`` must match the beginning of the source unit name resulting from the import.
+- ``target`` is the value the prefix is replaced with.
+
+For example, if you clone https://github.com/ethereum/dapp-bin/ locally to ``/project/dapp-bin``
+and run the compiler with:
+
+.. code-block:: bash
+
+ solc github.com/ethereum/dapp-bin/=dapp-bin/ --base-path /project source.sol
+
+you can use the following in your source file:
+
+.. code-block:: solidity
+
+ import "github.com/ethereum/dapp-bin/library/math.sol"; // source unit name: dapp-bin/library/math.sol
+
+The compiler will look for the file in the VFS under ``dapp-bin/library/math.sol``.
+If the file is not available there, the source unit name will be passed to the Host Filesystem
+Loader, which will then look in ``/project/dapp-bin/library/iterable_mapping.sol``.
+
+.. warning::
+
+ Information about remappings is stored in contract metadata.
+ Since the binary produced by the compiler has a hash of the metadata embedded in it, any
+ modification to the remappings will result in different bytecode.
+
+ For this reason you should be careful not to include any local information in remapping targets.
+ For example if your library is located in ``/home/user/packages/mymath/math.sol``, a remapping
+ like ``@math/=/home/user/packages/mymath/`` would result in your home directory being included in
+ the metadata.
+ To be able to reproduce the same bytecode with such a remapping on a different machine, you
+ would need to recreate parts of your local directory structure in the VFS and (if you rely on
+ Host Filesystem Loader) also in the host filesystem.
+
+As a more complex example, suppose you rely on a module that uses an old version of dapp-bin that
+you checked out to ``/project/dapp-bin_old``, then you can run:
+
+.. code-block:: bash
+
+ solc module1:github.com/ethereum/dapp-bin/=dapp-bin/ \
+ module2:github.com/ethereum/dapp-bin/=dapp-bin_old/ \
+ --base-path /project \
+ source.sol
+
+This means that all imports in ``module2`` point to the old version but imports in ``module1``
+point to the new version.
+
+Here are the detailed rules governing the behaviour of remappings:
+
+#. **Remappings only affect the translation between import paths and source unit names.**
+
+ Source unit names added to the VFS in any other way cannot be remapped.
+ For example the paths you specify on the command-line and the ones in ``sources.urls`` in
+ Standard JSON are not affected.
+
+ .. code-block:: bash
+
+ solc /project/=/contracts/ /project/contract.sol # source unit name: /project/contract.sol
+
+ In the example above the compiler will load the source code from ``/project/contract.sol`` and
+ place it under that exact source unit name in the VFS, not under ``/contract/contract.sol``.
+
+#. **Context and prefix must match source unit names, not import paths.**
+
+ - This means that you cannot remap ``./`` or ``../`` directly since they are replaced during
+ the translation to source unit name but you can remap the part of the name they are replaced
+ with:
+
+ .. code-block:: bash
+
+ solc ./=a/ /project/=b/ /project/contract.sol # source unit name: /project/contract.sol
+
+ .. code-block:: solidity
+ :caption: /project/contract.sol
+
+ import "./util.sol" as util; // source unit name: b/util.sol
+
+ - You cannot remap base path or any other part of the path that is only added internally by an
+ import callback:
+
+ .. code-block:: bash
+
+ solc /project/=/contracts/ /project/contract.sol --base-path /project # source unit name: /project/contract.sol
+
+ .. code-block:: solidity
+ :caption: /project/contract.sol
+
+ import "util.sol" as util; // source unit name: util.sol
+
+#. **Target is inserted directly into the source unit name and does not necessarily have to be a valid path.**
+
+ - It can be anything as long as the import callback can handle it.
+ In case of the Host Filesystem Loader this includes also relative paths.
+ When using the JavaScript interface you can even use URLs and abstract identifiers if
+ your callback can handle them.
+
+ - Remapping happens after relative imports have already been resolved into source unit names.
+ This means that targets starting with ``./`` and ``../`` have no special meaning and are
+ relative to the base path rather than to the location of the source file.
+
+ - Remapping targets are not normalized so ``@root/=./a/b//`` will remap ``@root/contract.sol``
+ to ``./a/b//contract.sol`` and not ``a/b/contract.sol``.
+
+ - If the target does not end with a slash, the compiler will not add one automatically:
+
+ .. code-block:: bash
+
+ solc /project/=/contracts /project/contract.sol # source unit name: /project/contract.sol
+
+ .. code-block:: solidity
+ :caption: /project/contract.sol
+
+ import "/project/util.sol" as util; // source unit name: /contractsutil.sol
+
+#. **Context and prefix are patterns and matches must be exact.**
+
+ - ``a//b=c`` will not match ``a/b``.
+ - source unit names are not normalized so ``a/b=c`` will not match ``a//b`` either.
+ - Parts of file and directory names can match as well.
+ ``/newProject/con:/new=old`` will match ``/newProject/contract.sol`` and remap it to
+ ``oldProject/contract.sol``.
+
+#. **At most one remapping is applied to a single import.**
+
+ - If multiple remappings match the same source unit name, the one with the longest matching
+ prefix is chosen.
+ - If prefixes are identical, the one specified last wins.
+ - Remappings do not work on other remappings. For example ``a=b b=c c=d`` will not result in ``a``
+ being remapped to ``d``.
+
+#. **Prefix cannot be empty but context and target are optional.**
+
+ If ``target`` is omitted, it defaults to the value of the ``prefix``.
+
+.. index:: Remix IDE, file://
+
+Using URLs in imports
+=====================
+
+Most URL prefixes such as ``https://`` or ``data://`` have no special meaning in import paths.
+The only exception is ``file://`` which is stripped from source unit names by the Host Filesystem
+Loader.
+
+When compiling locally you can use import remapping to replace the protocol and domain part with a
+local path:
+
+.. code-block:: bash
+
+ solc :https://github.com/ethereum/dapp-bin=/usr/local/dapp-bin contract.sol
+
+Note the leading ``:``, which is necessary when the remapping context is empty.
+Otherwise the ``https:`` part would be interpreted by the compiler as the context.
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 268c6e161..038c22b7c 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,3 +1,6 @@
sphinx_rtd_theme>=0.3.1
pygments-lexer-solidity>=0.7.0
sphinx-a4doc>=1.2.1
+
+# Sphinx 2.1.0 is the oldest version that accepts a lexer class in add_lexer()
+sphinx>=2.1.0
diff --git a/docs/robots.txt.template b/docs/robots.txt.template
new file mode 100644
index 000000000..3b7431d74
--- /dev/null
+++ b/docs/robots.txt.template
@@ -0,0 +1,15 @@
+User-Agent: *
+Sitemap: http://docs.soliditylang.org/sitemap.xml
+Host: docs.soliditylang.org
+
+Allow: /en/latest/
+Allow: /en/v0.7.6/
+Allow: /en/v{{ LATEST_VERSION }}/
+Allow: /_/downloads/en/latest/
+Allow: /_/downloads/en/0.7.6/
+Allow: /_/downloads/en/{{ LATEST_VERSION }}/
+
+# Prevent documentation for the development branches and older Solidity
+# versions from showing up in search results.
+Disallow: /en/*
+Disallow: /_/downloads/en/*
diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst
index e807d301e..c59f4c750 100644
--- a/docs/security-considerations.rst
+++ b/docs/security-considerations.rst
@@ -56,7 +56,7 @@ to call back into A before this interaction is completed. To give an example,
the following code contains a bug (it is just a snippet and not a
complete contract):
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -80,7 +80,7 @@ basically retrieve all the Ether in the contract. In particular, the
following contract will allow an attacker to refund multiple times
as it uses ``call`` which forwards all remaining gas by default:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;
@@ -100,7 +100,7 @@ as it uses ``call`` which forwards all remaining gas by default:
To avoid re-entrancy, you can use the Checks-Effects-Interactions pattern as
outlined further below:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -198,7 +198,7 @@ tx.origin
Never use tx.origin for authorization. Let's say you have a wallet contract like this:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -218,7 +218,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
Now someone tricks you into sending Ether to the address of this attack wallet:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -251,7 +251,7 @@ They resemble integers when the values are small, but cannot represent arbitrari
The following code causes an overflow because the result of the addition is too large
to be stored in the type ``uint8``:
-::
+.. code-block:: solidity
uint8 x = 255;
uint8 y = 1;
@@ -289,7 +289,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The
``mapping`` is also ignored in assignments of structs or arrays containing a
``mapping``.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -346,7 +346,7 @@ Recommendations
Take Warnings Seriously
=======================
-If the compiler warns you about something, you should better change it.
+If the compiler warns you about something, you should change it.
Even if you do not think that this particular warning has security
implications, there might be another issue buried beneath it.
Any compiler warning we issue can be silenced by slight changes to the
diff --git a/docs/smtchecker.rst b/docs/smtchecker.rst
index 6ce369bc6..6fc0a1c57 100644
--- a/docs/smtchecker.rst
+++ b/docs/smtchecker.rst
@@ -503,6 +503,18 @@ which has the following form:
.. _smtchecker_engines:
+Natspec Function Abstraction
+============================
+
+Certain functions including common math methods such as ``pow``
+and ``sqrt`` may be too complex to be analyzed in a fully automated way.
+These functions can be annotated with Natspec tags that indicate to the
+SMTChecker that these functions should be abstracted. This means that the
+body of the function is not used, and when called, the function will:
+
+- Return a nondeterministic value, and either keep the state variables unchanged if the abstracted function is view/pure, or also set the state variables to nondeterministic values otherwise. This can be used via the annotation ``/// @custom:smtchecker abstract-function-nondet``.
+- Act as an uninterpreted function. This means that the semantics of the function (given by the body) are ignored, and the only property this function has is that given the same input it guarantees the same output. This is currently under development and will be available via the annotation ``/// @custom:smtchecker abstract-function-uf``.
+
Model Checking Engines
======================
@@ -654,7 +666,7 @@ the arguments.
Using abstraction means loss of precise knowledge, but in many cases it does
not mean loss of proving power.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0;
@@ -701,7 +713,7 @@ location is erased.
If the type is nested, the knowledge removal also includes all the prefix base
types.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0;
diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst
index ae6f41e02..e776c4eca 100644
--- a/docs/structure-of-a-contract.rst
+++ b/docs/structure-of-a-contract.rst
@@ -24,7 +24,7 @@ State Variables
State variables are variables whose values are permanently stored in contract
storage.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -47,7 +47,7 @@ Functions are the executable units of code. Functions are usually
defined inside a contract, but they can also be defined outside of
contracts.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.7.0 <0.9.0;
@@ -81,7 +81,7 @@ is not possible.
Like functions, modifiers can be :ref:`overridden `.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
@@ -109,7 +109,7 @@ Events
Events are convenience interfaces with the EVM logging facilities.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.21 <0.9.0;
@@ -137,7 +137,7 @@ In comparison to string descriptions, errors are much cheaper and allow you
to encode additional data. You can use NatSpec to describe the error to
the user.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -168,7 +168,7 @@ Struct Types
Structs are custom defined types that can group several variables (see
:ref:`structs` in types section).
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -190,7 +190,7 @@ Enum Types
Enums can be used to create custom types with a finite set of 'constant values' (see
:ref:`enums` in types section).
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
diff --git a/docs/style-guide.rst b/docs/style-guide.rst
index 34cf6c5cb..edb3b25ee 100644
--- a/docs/style-guide.rst
+++ b/docs/style-guide.rst
@@ -53,7 +53,9 @@ Blank Lines
Surround top level declarations in solidity source with two blank lines.
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -72,7 +74,9 @@ Yes::
// ...
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -92,7 +96,9 @@ Within a contract surround function declarations with a single blank line.
Blank lines may be omitted between groups of related one-liners (such as stub functions for an abstract contract)
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -113,7 +119,9 @@ Yes::
}
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -150,7 +158,9 @@ Wrapped lines should conform to the following guidelines.
Function Calls
-Yes::
+Yes:
+
+.. code-block:: solidity
thisFunctionCallIsReallyLong(
longArgument1,
@@ -158,7 +168,9 @@ Yes::
longArgument3
);
-No::
+No:
+
+.. code-block:: solidity
thisFunctionCallIsReallyLong(longArgument1,
longArgument2,
@@ -188,7 +200,9 @@ No::
Assignment Statements
-Yes::
+Yes:
+
+.. code-block:: solidity
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(
argument1,
@@ -197,7 +211,9 @@ Yes::
argument4
);
-No::
+No:
+
+.. code-block:: solidity
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1,
argument2,
@@ -206,7 +222,9 @@ No::
Event Definitions and Event Emitters
-Yes::
+Yes:
+
+.. code-block:: solidity
event LongAndLotsOfArgs(
address sender,
@@ -224,7 +242,9 @@ Yes::
options
);
-No::
+No:
+
+.. code-block:: solidity
event LongAndLotsOfArgs(address sender,
address recipient,
@@ -248,7 +268,9 @@ Imports
Import statements should always be placed at the top of the file.
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -263,7 +285,9 @@ Yes::
// ...
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -297,7 +321,9 @@ Functions should be grouped according to their visibility and ordered:
Within a grouping, place the ``view`` and ``pure`` functions last.
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -333,7 +359,9 @@ Yes::
// ...
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -370,11 +398,15 @@ Avoid extraneous whitespace in the following situations:
Immediately inside parenthesis, brackets or braces, with the exception of single line function declarations.
-Yes::
+Yes:
+
+.. code-block:: solidity
spam(ham[1], Coin({name: "ham"}));
-No::
+No:
+
+.. code-block:: solidity
spam( ham[ 1 ], Coin( { name: "ham" } ) );
@@ -384,23 +416,31 @@ Exception::
Immediately before a comma, semicolon:
-Yes::
+Yes:
+
+.. code-block:: solidity
function spam(uint i, Coin coin) public;
-No::
+No:
+
+.. code-block:: solidity
function spam(uint i , Coin coin) public ;
More than one space around an assignment or other operator to align with another:
-Yes::
+Yes:
+
+.. code-block:: solidity
x = 1;
y = 2;
long_variable = 3;
-No::
+No:
+
+.. code-block:: solidity
x = 1;
y = 2;
@@ -408,7 +448,9 @@ No::
Don't include a whitespace in the receive and fallback functions:
-Yes::
+Yes:
+
+.. code-block:: solidity
receive() external payable {
...
@@ -418,7 +460,9 @@ Yes::
...
}
-No::
+No:
+
+.. code-block:: solidity
receive () external payable {
...
@@ -440,7 +484,9 @@ should:
declaration.
* The opening brace should be preceded by a single space.
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -452,7 +498,9 @@ Yes::
}
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -473,7 +521,9 @@ Additionally there should be a single space between the control structures
conditional, as well as a single space between the conditional parenthetic
block and the opening brace.
-Yes::
+Yes:
+
+.. code-block:: solidity
if (...) {
...
@@ -483,7 +533,9 @@ Yes::
...
}
-No::
+No:
+
+.. code-block:: solidity
if (...)
{
@@ -499,12 +551,16 @@ No::
For control structures whose body contains a single statement, omitting the
braces is ok *if* the statement is contained on a single line.
-Yes::
+Yes:
+
+.. code-block:: solidity
if (x < 10)
x += 1;
-No::
+No:
+
+.. code-block:: solidity
if (x < 10)
someArray.push(Coin({
@@ -516,7 +572,9 @@ For ``if`` blocks which have an ``else`` or ``else if`` clause, the ``else`` sho
placed on the same line as the ``if``'s closing brace. This is an exception compared
to the rules of other block-like structures.
-Yes::
+Yes:
+
+.. code-block:: solidity
if (x < 3) {
x += 1;
@@ -532,7 +590,9 @@ Yes::
else
x -= 1;
-No::
+No:
+
+.. code-block:: solidity
if (x < 3) {
x += 1;
@@ -552,7 +612,9 @@ declaration.
The opening brace should be preceded by a single space.
-Yes::
+Yes:
+
+.. code-block:: solidity
function increment(uint x) public pure returns (uint) {
return x + 1;
@@ -562,7 +624,9 @@ Yes::
return x + 1;
}
-No::
+No:
+
+.. code-block:: solidity
function increment(uint x) public pure returns (uint)
{
@@ -588,7 +652,9 @@ The modifier order for a function should be:
4. Override
5. Custom modifiers
-Yes::
+Yes:
+
+.. code-block:: solidity
function balance(uint from) public view override returns (uint) {
return balanceOf[from];
@@ -598,7 +664,9 @@ Yes::
selfdestruct(owner);
}
-No::
+No:
+
+.. code-block:: solidity
function balance(uint from) public override view returns (uint) {
return balanceOf[from];
@@ -613,7 +681,9 @@ it's own line at the same indentation level as the function body. The closing
parenthesis and opening bracket should be placed on their own line as well at
the same indentation level as the function declaration.
-Yes::
+Yes:
+
+.. code-block:: solidity
function thisFunctionHasLotsOfArguments(
address a,
@@ -628,7 +698,9 @@ Yes::
doSomething();
}
-No::
+No:
+
+.. code-block:: solidity
function thisFunctionHasLotsOfArguments(address a, address b, address c,
address d, address e, address f) public {
@@ -657,7 +729,9 @@ No::
If a long function declaration has modifiers, then each modifier should be
dropped to its own line.
-Yes::
+Yes:
+
+.. code-block:: solidity
function thisFunctionNameIsReallyLong(address x, address y, address z)
public
@@ -681,7 +755,9 @@ Yes::
doSomething();
}
-No::
+No:
+
+.. code-block:: solidity
function thisFunctionNameIsReallyLong(address x, address y, address z)
public
@@ -707,7 +783,9 @@ No::
Multiline output parameters and return statements should follow the same style recommended for wrapping long lines found in the :ref:`Maximum Line Length ` section.
-Yes::
+Yes:
+
+.. code-block:: solidity
function thisFunctionNameIsReallyLong(
address a,
@@ -730,7 +808,9 @@ Yes::
);
}
-No::
+No:
+
+.. code-block:: solidity
function thisFunctionNameIsReallyLong(
address a,
@@ -753,7 +833,9 @@ For constructor functions on inherited contracts whose bases require arguments,
it is recommended to drop the base constructors onto new lines in the same
manner as modifiers if the function declaration is long or hard to read.
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -784,7 +866,9 @@ Yes::
}
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -834,7 +918,9 @@ No::
When declaring short functions with a single statement, it is permissible to do it on a single line.
-Permissible::
+Permissible:
+
+.. code-block:: solidity
function shortFunction() public { doSomething(); }
@@ -849,14 +935,18 @@ In variable declarations, do not separate the keyword ``mapping`` from its
type by a space. Do not separate any nested ``mapping`` keyword from its type by
whitespace.
-Yes::
+Yes:
+
+.. code-block:: solidity
mapping(uint => uint) map;
mapping(address => bool) registeredAddresses;
mapping(uint => mapping(bool => Data[])) public data;
mapping(uint => mapping(uint => s)) data;
-No::
+No:
+
+.. code-block:: solidity
mapping (uint => uint) map;
mapping( address => bool ) registeredAddresses;
@@ -869,11 +959,15 @@ Variable Declarations
Declarations of array variables should not have a space between the type and
the brackets.
-Yes::
+Yes:
+
+.. code-block:: solidity
uint[] x;
-No::
+No:
+
+.. code-block:: solidity
uint [] x;
@@ -883,26 +977,34 @@ Other Recommendations
* Strings should be quoted with double-quotes instead of single-quotes.
-Yes::
+Yes:
+
+.. code-block:: solidity
str = "foo";
str = "Hamlet says, 'To be or not to be...'";
-No::
+No:
+
+.. code-block:: solidity
str = 'bar';
str = '"Be yourself; everyone else is already taken." -Oscar Wilde';
* Surround operators with a single space on either side.
-Yes::
+Yes:
+
+.. code-block:: solidity
x = 3;
x = 100 / 10;
x += 3 + 4;
x |= y && z;
-No::
+No:
+
+.. code-block:: solidity
x=3;
x = 100/10;
@@ -914,13 +1016,17 @@ No::
improved readability for complex statement. You should always use the same
amount of whitespace on either side of an operator:
-Yes::
+Yes:
+
+.. code-block:: solidity
x = 2**3 + 5;
x = 2*y + 3*z;
x = (a+b) * (a-b);
-No::
+No:
+
+.. code-block:: solidity
x = 2** 3 + 5;
x = y+z;
@@ -1005,7 +1111,9 @@ Contract and Library Names
As shown in the example below, if the contract name is ``Congress`` and the library name is ``Owned``, then their associated filenames should be ``Congress.sol`` and ``Owned.sol``.
-Yes::
+Yes:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -1028,7 +1136,9 @@ Yes::
}
}
-and in ``Congress.sol``::
+and in ``Congress.sol``:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -1040,7 +1150,9 @@ and in ``Congress.sol``::
//...
}
-No::
+No:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
@@ -1063,7 +1175,9 @@ No::
}
}
-and in ``Congress.sol``::
+and in ``Congress.sol``:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.0;
@@ -1147,7 +1261,9 @@ triple slash (``///``) or a double asterisk block (``/** ... */``) and
they should be used directly above function declarations or statements.
For example, the contract from :ref:`a simple smart contract ` with the comments
-added looks like the one below::
+added looks like the one below:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
diff --git a/docs/types/conversion.rst b/docs/types/conversion.rst
index 38e0ca6f1..7e266d1bd 100644
--- a/docs/types/conversion.rst
+++ b/docs/types/conversion.rst
@@ -32,7 +32,7 @@ in the ``uint16`` type. The resulting type of the expression ``y + z`` is ``uint
Because it is assigned to a variable of type ``uint32`` another implicit conversion
is performed after the addition.
-::
+.. code-block:: solidity
uint8 y;
uint16 z;
@@ -50,7 +50,7 @@ result is what you want and expect!
Take the following example that converts a negative ``int`` to a ``uint``:
-::
+.. code-block:: solidity
int y = -3;
uint x = uint(y);
@@ -59,13 +59,17 @@ At the end of this code snippet, ``x`` will have the value ``0xfffff..fd`` (64 h
characters), which is -3 in the two's complement representation of 256 bits.
If an integer is explicitly converted to a smaller type, higher-order bits are
-cut off::
+cut off:
+
+.. code-block:: solidity
uint32 a = 0x12345678;
uint16 b = uint16(a); // b will be 0x5678 now
If an integer is explicitly converted to a larger type, it is padded on the left (i.e., at the higher order end).
-The result of the conversion will compare equal to the original integer::
+The result of the conversion will compare equal to the original integer:
+
+.. code-block:: solidity
uint16 a = 0x1234;
uint32 b = uint32(a); // b will be 0x00001234 now
@@ -73,14 +77,18 @@ The result of the conversion will compare equal to the original integer::
Fixed-size bytes types behave differently during conversions. They can be thought of as
sequences of individual bytes and converting to a smaller type will cut off the
-sequence::
+sequence:
+
+.. code-block:: solidity
bytes2 a = 0x1234;
bytes1 b = bytes1(a); // b will be 0x12
If a fixed-size bytes type is explicitly converted to a larger type, it is padded on
the right. Accessing the byte at a fixed index will result in the same value before and
-after the conversion (if the index is still in range)::
+after the conversion (if the index is still in range):
+
+.. code-block:: solidity
bytes2 a = 0x1234;
bytes4 b = bytes4(a); // b will be 0x12340000
@@ -91,7 +99,9 @@ Since integers and fixed-size byte arrays behave differently when truncating or
padding, explicit conversions between integers and fixed-size byte arrays are only allowed,
if both have the same size. If you want to convert between integers and fixed-size byte arrays of
different size, you have to use intermediate conversions that make the desired truncation and padding
-rules explicit::
+rules explicit:
+
+.. code-block:: solidity
bytes2 a = 0x1234;
uint32 b = uint16(a); // b will be 0x00001234
@@ -103,7 +113,7 @@ rules explicit::
In case the array is longer than the target fixed bytes type, truncation at the end will happen.
If the array is shorter than the target type, it will be padded with zeros at the end.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.5;
@@ -129,7 +139,9 @@ Integer Types
-------------
Decimal and hexadecimal number literals can be implicitly converted to any integer type
-that is large enough to represent it without truncation::
+that is large enough to represent it without truncation:
+
+.. code-block:: solidity
uint8 a = 12; // fine
uint32 b = 1234; // fine
@@ -146,7 +158,9 @@ Fixed-Size Byte Arrays
Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal
number literals can be, but only if the number of hex digits exactly fits the size of the bytes
type. As an exception both decimal and hexadecimal literals which have a value of zero can be
-converted to any fixed-size bytes type::
+converted to any fixed-size bytes type:
+
+.. code-block:: solidity
bytes2 a = 54321; // not allowed
bytes2 b = 0x12; // not allowed
@@ -157,7 +171,9 @@ converted to any fixed-size bytes type::
bytes4 g = 0x0; // fine
String literals and hex string literals can be implicitly converted to fixed-size byte arrays,
-if their number of characters matches the size of the bytes type::
+if their number of characters matches the size of the bytes type:
+
+.. code-block:: solidity
bytes2 a = hex"1234"; // fine
bytes2 b = "xy"; // fine
diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst
index edf04aed2..29a00a196 100644
--- a/docs/types/mapping-types.rst
+++ b/docs/types/mapping-types.rst
@@ -40,7 +40,7 @@ an Ethereum address to an unsigned integer value. As ``uint`` is a value type, t
returns a value that matches the type, which you can see in the ``MappingUser``
contract that returns the value at the specified address.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -66,7 +66,7 @@ The example below is a simplified version of an
``_allowances`` is an example of a mapping type inside another mapping type.
The example below uses ``_allowances`` to record the amount someone else is allowed to withdraw from your account.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
@@ -121,7 +121,7 @@ top of them and iterate over that. For example, the code below implements an
``IterableMapping`` library that the ``User`` contract then adds data too, and
the ``sum`` function iterates over to sum all the values.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.8 <0.9.0;
diff --git a/docs/types/operators.rst b/docs/types/operators.rst
index 883f8d4b7..733dc806d 100644
--- a/docs/types/operators.rst
+++ b/docs/types/operators.rst
@@ -40,7 +40,7 @@ This distinction is visible when ``a`` is reference variable: It
will only reset ``a`` itself, not the
value it referred to previously.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst
index 8d21221b4..b6a36fc6e 100644
--- a/docs/types/reference-types.rst
+++ b/docs/types/reference-types.rst
@@ -60,7 +60,7 @@ Data locations are not only relevant for persistency of data, but also for the s
variables of storage struct type, even if the local variable
itself is just a reference.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
@@ -114,7 +114,7 @@ Indices are zero-based, and access is in the opposite direction of the
declaration.
For example, if you have a variable ``uint[][5] memory x``, you access the
-second ``uint`` in the third dynamic array using ``x[2][1]``, and to access the
+seventh ``uint`` in the third dynamic array using ``x[2][6]``, and to access the
third dynamic array, use ``x[2]``. Again,
if you have an array ``T[5] a`` for a type ``T`` that can also be an array,
then ``a[2]`` always has type ``T``.
@@ -171,7 +171,7 @@ You can concatenate a variable number of ``bytes`` or ``bytes1 ... bytes32`` usi
The function returns a single ``bytes memory`` array that contains the contents of the arguments without padding.
If you want to use string parameters or other types, you need to convert them to ``bytes`` or ``bytes1``/.../``bytes32`` first.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
@@ -200,7 +200,7 @@ or create a new memory array and copy every element.
As all variables in Solidity, the elements of newly allocated arrays are always initialized
with the :ref:`default value`.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -239,7 +239,7 @@ In the example below, the type of ``[1, 2, 3]`` is
you want the result to be a ``uint[3] memory`` type, you need to convert
the first element to ``uint``.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -261,7 +261,7 @@ Since fixed-size memory arrays of different type cannot be converted into each o
(even if the base types can), you always have to specify a common base type explicitly
if you want to use two-dimensional array literals:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -278,7 +278,7 @@ if you want to use two-dimensional array literals:
Fixed size memory arrays cannot be assigned to dynamically-sized
memory arrays, i.e. the following is not possible:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
@@ -298,7 +298,7 @@ complications because of how arrays are passed in the ABI.
If you want to initialize dynamically-sized arrays, you have to assign the
individual elements:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -356,7 +356,7 @@ Array Members
that return dynamic arrays, make sure to use an EVM that is set to
Byzantium mode.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
@@ -489,7 +489,7 @@ they only exist in intermediate expressions.
Array slices are useful to ABI-decode secondary data passed in function parameters:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.8.4 <0.9.0;
@@ -528,7 +528,7 @@ Structs
Solidity provides a way to define new types in the form of structs, which is
shown in the following example:
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst
index ee94ed60a..d6a30d106 100644
--- a/docs/types/value-types.rst
+++ b/docs/types/value-types.rst
@@ -66,16 +66,23 @@ Shifts
^^^^^^
The result of a shift operation has the type of the left operand, truncating the result to match the type.
-Right operand must be unsigned type. Trying to shift by signed type will produce a compilation error.
+The right operand must be of unsigned type, trying to shift by an signed type will produce a compilation error.
-- For positive and negative ``x`` values, ``x << y`` is equivalent to ``x * 2**y``.
-- For positive ``x`` values, ``x >> y`` is equivalent to ``x / 2**y``.
-- For negative ``x`` values, ``x >> y`` is equivalent to ``(x + 1) / 2**y - 1`` (which is the same as dividing ``x`` by ``2**y`` while rounding down towards negative infinity).
+Shifts can be "simulated" using multiplication by powers of two in the following way. Note that the truncation
+to the type of the left operand is always performed at the end, but not mentioned explicitly.
+
+- ``x << y`` is equivalent to the mathematical expression ``x * 2**y``.
+- ``x >> y`` is equivalent to the mathematical expression ``x / 2**y``, rounded towards negative infinity.
.. warning::
- Before version ``0.5.0`` a right shift ``x >> y`` for negative ``x`` was equivalent to ``x / 2**y``,
+ Before version ``0.5.0`` a right shift ``x >> y`` for negative ``x`` was equivalent to
+ the mathematical expression ``x / 2**y`` rounded towards zero,
i.e., right shifts used rounding up (towards zero) instead of rounding down (towards negative infinity).
+.. note::
+ Overflow checks are never performed for shift operations as they are done for arithmetic operations.
+ Instead, the result is always truncated.
+
Addition, Subtraction and Multiplication
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -231,7 +238,7 @@ For a quick reference of all members of address, see :ref:`address_related`.
It is possible to query the balance of an address using the property ``balance``
and to send Ether (in units of wei) to a payable address using the ``transfer`` function:
-::
+.. code-block:: solidity
address payable x = address(0x123);
address myAddress = address(this);
@@ -265,7 +272,9 @@ return the success condition (as a ``bool``) and the returned data
The functions ``abi.encode``, ``abi.encodePacked``, ``abi.encodeWithSelector``
and ``abi.encodeWithSignature`` can be used to encode structured data.
-Example::
+Example:
+
+.. code-block:: solidity
bytes memory payload = abi.encodeWithSignature("register(string)", "MyName");
(bool success, bytes memory returnData) = address(nameReg).call(payload);
@@ -284,15 +293,21 @@ Example::
arbitrary arguments and would also handle a first argument of type
``bytes4`` differently. These edge cases were removed in version 0.5.0.
-It is possible to adjust the supplied gas with the ``gas`` modifier::
+It is possible to adjust the supplied gas with the ``gas`` modifier:
+
+.. code-block:: solidity
address(nameReg).call{gas: 1000000}(abi.encodeWithSignature("register(string)", "MyName"));
-Similarly, the supplied Ether value can be controlled too::
+Similarly, the supplied Ether value can be controlled too:
+
+.. code-block:: solidity
address(nameReg).call{value: 1 ether}(abi.encodeWithSignature("register(string)", "MyName"));
-Lastly, these modifiers can be combined. Their order does not matter::
+Lastly, these modifiers can be combined. Their order does not matter:
+
+.. code-block:: solidity
address(nameReg).call{gas: 1000000, value: 1 ether}(abi.encodeWithSignature("register(string)", "MyName"));
@@ -305,8 +320,8 @@ Since byzantium ``staticcall`` can be used as well. This is basically the same a
All three functions ``call``, ``delegatecall`` and ``staticcall`` are very low-level functions and should only be used as a *last resort* as they break the type-safety of Solidity.
-The ``gas`` option is available on all three methods, while the ``value`` option is not
-supported for ``delegatecall``.
+The ``gas`` option is available on all three methods, while the ``value`` option is only available
+on ``call``.
.. note::
It is best to avoid relying on hardcoded gas values in your smart contract code,
@@ -476,7 +491,7 @@ regardless of the type of the right (exponent) operand.
for the type of ``2.5`` and ``uint128``, the Solidity compiler does not accept
this code.
-::
+.. code-block:: solidity
uint128 a = 1;
uint128 b = 2.5 + a + 0.5;
@@ -529,7 +544,7 @@ Unicode Literals
While regular string literals can only contain ASCII, Unicode literals – prefixed with the keyword ``unicode`` – can contain any valid UTF-8 sequence.
They also support the very same escape sequences as regular string literals.
-::
+.. code-block:: solidity
string memory a = unicode"Hello 😃";
@@ -567,7 +582,7 @@ The data representation is the same as for enums in C: The options are represent
subsequent unsigned integer values starting from ``0``.
-::
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -619,7 +634,9 @@ contract internally.
External functions consist of an address and a function signature and they can
be passed via and returned from external function calls.
-Function types are notated as follows::
+Function types are notated as follows:
+
+.. code-block:: solidity
function () {internal|external} [pure|view|payable] [returns ()]
@@ -688,7 +705,9 @@ External (or public) functions have the following members:
respectively. See :ref:`External Function Calls ` for
more information.
-Example that shows how to use the members::
+Example that shows how to use the members:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.4 <0.9.0;
@@ -704,7 +723,9 @@ Example that shows how to use the members::
}
}
-Example that shows how to use internal function types::
+Example that shows how to use internal function types:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
@@ -762,7 +783,9 @@ Example that shows how to use internal function types::
}
}
-Another example that uses external function types::
+Another example that uses external function types:
+
+.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index 1cad59e42..2e912ae84 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -9,7 +9,7 @@ Ether Units
A literal number can take a suffix of ``wei``, ``gwei`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
-::
+.. code-block:: solidity
assert(1 wei == 1);
assert(1 gwei == 1e9);
@@ -45,7 +45,9 @@ library has to be updated by an external oracle.
The suffix ``years`` has been removed in version 0.5.0 due to the reasons above.
These suffixes cannot be applied to variables. For example, if you want to
-interpret a function parameter in days, you can in the following way::
+interpret a function parameter in days, you can in the following way:
+
+.. code-block:: solidity
function f(uint start, uint daysAfter) public {
if (block.timestamp >= start + daysAfter * 1 days) {
@@ -68,7 +70,7 @@ or are general-use utility functions.
Block and Transaction Properties
--------------------------------
-- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks
+- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block when ``blocknumber`` is one of the 256 most recent blocks; otherwise returns zero
- ``block.chainid`` (``uint``): current chain id
- ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst
index 1ccebf359..a023a8877 100644
--- a/docs/using-the-compiler.rst
+++ b/docs/using-the-compiler.rst
@@ -2,7 +2,7 @@
Using the Compiler
******************
-.. index:: ! commandline compiler, compiler;commandline, ! solc, ! linker
+.. index:: ! commandline compiler, compiler;commandline, ! solc
.. _commandline-compiler:
@@ -33,11 +33,13 @@ This parameter has effects on the following (this might change in the future):
- the size of the binary search in the function dispatch routine
- the way constants like large numbers or strings are stored
-Path Remapping
---------------
+.. index:: allowed paths, --allow-paths, base path, --base-path
+
+Base Path and Import Remapping
+------------------------------
The commandline compiler will automatically read imported files from the filesystem, but
-it is also possible to provide path redirects using ``prefix=path`` in the following way:
+it is also possible to provide :ref:`path redirects ` using ``prefix=path`` in the following way:
::
@@ -49,19 +51,24 @@ This essentially instructs the compiler to search for anything starting with
the remapping targets and outside of the directories where explicitly specified source
files reside, so things like ``import "/etc/passwd";`` only work if you add ``/=/`` as a remapping.
-An empty remapping prefix is not allowed.
-
-If there are multiple matches due to remappings, the one with the longest common prefix is selected.
-
-When accessing the filesystem to search for imports, all paths are treated as if they were fully qualified paths.
-This behaviour can be customized by adding the command line option ``--base-path`` with a path to be prepended
-before each filesystem access for imports is performed. Furthermore, the part added via ``--base-path``
-will not appear in the contract metadata.
-
-For security reasons the compiler has restrictions what directories it can access. Paths (and their subdirectories) of source files specified on the commandline and paths defined by remappings are allowed for import statements, but everything else is rejected. Additional paths (and their subdirectories) can be allowed via the ``--allow-paths /sample/path,/another/sample/path`` switch.
+When accessing the filesystem to search for imports, :ref:`paths that do not start with ./
+or ../ ` are treated as relative to the directory specified using
+``--base-path`` option (or the current working directory if base path is not specified).
+Furthermore, the part added via ``--base-path`` will not appear in the contract metadata.
+For security reasons the compiler has restrictions on what directories it can access.
+Directories of source files specified on the command line and target paths of
+remappings are automatically allowed to be accessed by the file reader, but everything
+else is rejected by default.
+Additional paths (and their subdirectories) can be allowed via the
+``--allow-paths /sample/path,/another/sample/path`` switch.
Everything inside the path specified via ``--base-path`` is always allowed.
+The above is only a simplification of how the compiler handles import paths.
+For a detailed explanation with examples and discussion of corner cases please refer to the section on
+:ref:`path resolution `.
+
+.. index:: ! linker, ! --link, ! --libraries
.. _library-linking:
Library Linking
@@ -79,6 +86,8 @@ Either add ``--libraries "file.sol:Math=0x12345678901234567890123456789012345678
.. note::
Starting Solidity 0.8.1 accepts ``=`` as separator between library and address, and ``:`` as a separator is deprecated. It will be removed in the future. Currently ``--libraries "file.sol:Math:0x1234567890123456789012345678901234567890 file.sol:Heap:0xabCD567890123456789012345678901234567890"`` will work too.
+.. index:: --standard-json, --base-path
+
If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses. The process will always terminate in a "success" state and report any errors via the JSON output.
The option ``--base-path`` is also processed in standard-json mode.
@@ -158,11 +167,15 @@ at each version. Backward compatibility is not guaranteed between each version.
- Shifting operators use shifting opcodes and thus need less gas.
- ``petersburg``
- The compiler behaves the same way as with constantinople.
-- ``istanbul`` (**default**)
+- ``istanbul``
- Opcodes ``chainid`` and ``selfbalance`` are available in assembly.
-- ``berlin`` (**experimental**)
+- ``berlin`` (**default**)
+ - Gas costs for ``SLOAD``, ``*CALL``, ``BALANCE``, ``EXT*`` and ``SELFDESTRUCT`` increased. The
+ compiler assumes cold gas costs for such operations. This is relevant for gas estimation and
+ the optimizer.
+.. index:: ! standard JSON, ! --standard-json
.. _compiler-api:
Compiler Input and Output JSON Description
@@ -233,7 +246,10 @@ Input Description
"remappings": [ ":g=/dir" ],
// Optional: Optimizer settings
"optimizer": {
- // disabled by default
+ // Disabled by default.
+ // NOTE: enabled=false still leaves some optimizations on. See comments below.
+ // WARNING: Before version 0.8.6 omitting the 'enabled' key was not equivalent to setting
+ // it to false and would actually disable all the optimizations.
"enabled": true,
// Optimize for how many times you intend to run the code.
// Lower values will optimize more for initial deployment cost, higher
@@ -344,6 +360,7 @@ Input Description
// storageLayout - Slots, offsets and types of the contract's state variables.
// evm.assembly - New assembly format
// evm.legacyAssembly - Old-style assembly format in JSON
+ // evm.bytecode.functionDebugData - Debugging information at function level
// evm.bytecode.object - Bytecode object
// evm.bytecode.opcodes - Opcodes list
// evm.bytecode.sourceMap - Source mapping (useful for debugging)
@@ -476,6 +493,17 @@ Output Description
"legacyAssembly": {},
// Bytecode and related details.
"bytecode": {
+ // Debugging data at the level of functions.
+ "functionDebugData": {
+ // Now follows a set of functions including compiler-internal and
+ // user-defined function. The set does not have to be complete.
+ "@mint_13": { // Internal name of the function
+ "entryPoint": 128, // Byte offset into the bytecode where the function starts (optional)
+ "id": 13, // AST ID of the function definition or null for compiler-internal functions (optional)
+ "parameterSlots": 2, // Number of EVM stack slots for the function parameters (optional)
+ "returnSlots": 1 // Number of EVM stack slots for the return values (optional)
+ }
+ },
// The bytecode as a hex string.
"object": "00fe",
// Opcodes list (string)
diff --git a/docs/yul.rst b/docs/yul.rst
index 2c77e4402..55e8b824f 100644
--- a/docs/yul.rst
+++ b/docs/yul.rst
@@ -1076,6 +1076,23 @@ regular strings in native encoding. For code,
Above, ``Block`` refers to ``Block`` in the Yul code grammar explained in the previous chapter.
+.. note::
+
+ Data objects or sub-objects whose names contain a ``.`` can be defined
+ but it is not possible to access them through ``datasize``,
+ ``dataoffset`` or ``datacopy`` because ``.`` is used as a separator
+ to access objects inside another object.
+
+.. note::
+
+ The data object called ``".metadata"`` has a special meaning:
+ It cannot be accessed from code and is always appended to the very end of the
+ bytecode, regardless of its position in the object.
+
+ Other data objects with special significance might be added in the
+ future, but their names will always start with a ``.``.
+
+
An example Yul Object is shown below:
.. code-block:: yul
@@ -1155,9 +1172,8 @@ Yul Optimizer
The Yul optimizer operates on Yul code and uses the same language for input, output and
intermediate states. This allows for easy debugging and verification of the optimizer.
-Please see the
-`documentation in the source code `_
-for more details about its internals.
+Please refer to the general :ref:`optimizer documentation `
+for more details about the different optimization stages and how to use the optimizer.
If you want to use Solidity in stand-alone Yul mode, you activate the optimizer using ``--optimize``:
@@ -1167,7 +1183,7 @@ If you want to use Solidity in stand-alone Yul mode, you activate the optimizer
In Solidity mode, the Yul optimizer is activated together with the regular optimizer.
-Optimization step sequence
+Optimization Step Sequence
--------------------------
By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly.
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index 50be995a8..f63f3ede6 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -348,12 +348,18 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices)
return root;
}
-AssemblyItem Assembly::namedTag(string const& _name)
+AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional _sourceID)
{
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
- if (!m_namedTags.count(_name))
- m_namedTags[_name] = static_cast(newTag().data());
- return AssemblyItem{Tag, m_namedTags.at(_name)};
+ if (m_namedTags.count(_name))
+ {
+ assertThrow(m_namedTags.at(_name).params == _params, AssemblyException, "");
+ assertThrow(m_namedTags.at(_name).returns == _returns, AssemblyException, "");
+ assertThrow(m_namedTags.at(_name).sourceID == _sourceID, AssemblyException, "");
+ }
+ else
+ m_namedTags[_name] = {static_cast(newTag().data()), _sourceID, _params, _returns};
+ return AssemblyItem{Tag, m_namedTags.at(_name).id};
}
AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier)
@@ -722,13 +728,16 @@ LinkerObject const& Assembly::assemble() const
ret.bytecode.resize(ret.bytecode.size() + 20);
break;
case Tag:
+ {
assertThrow(i.data() != 0, AssemblyException, "Invalid tag position.");
assertThrow(i.splitForeignPushTag().first == numeric_limits::max(), AssemblyException, "Foreign tag.");
+ size_t tagId = static_cast(i.data());
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
- assertThrow(m_tagPositionsInBytecode[static_cast(i.data())] == numeric_limits::max(), AssemblyException, "Duplicate tag position.");
- m_tagPositionsInBytecode[static_cast(i.data())] = ret.bytecode.size();
+ assertThrow(m_tagPositionsInBytecode[tagId] == numeric_limits::max(), AssemblyException, "Duplicate tag position.");
+ m_tagPositionsInBytecode[tagId] = ret.bytecode.size();
ret.bytecode.push_back(static_cast(Instruction::JUMPDEST));
break;
+ }
default:
assertThrow(false, InvalidOpcode, "Unexpected opcode while assembling.");
}
@@ -770,6 +779,17 @@ LinkerObject const& Assembly::assemble() const
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
toBigEndian(pos, r);
}
+ for (auto const& [name, tagInfo]: m_namedTags)
+ {
+ size_t position = m_tagPositionsInBytecode.at(tagInfo.id);
+ ret.functionDebugData[name] = {
+ position == numeric_limits::max() ? nullopt : optional{position},
+ tagInfo.sourceID,
+ tagInfo.params,
+ tagInfo.returns
+ };
+ }
+
for (auto const& dataItem: m_data)
{
auto references = dataRef.equal_range(dataItem.first);
diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h
index e16023ad9..4a0779ef7 100644
--- a/libevmasm/Assembly.h
+++ b/libevmasm/Assembly.h
@@ -30,11 +30,14 @@
#include
#include
+#include
+
#include
#include
#include
#include
+#include