Merge pull request #6188 from ethereum/develop

Release 0.5.5
This commit is contained in:
chriseth 2019-03-05 16:22:00 +01:00 committed by GitHub
commit 47a71e8f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
394 changed files with 8798 additions and 2530 deletions

View File

@ -56,10 +56,10 @@ jobs:
paths:
- boost_1_68_0
- store_artifacts:
path: build/libsolc/soljson.js
path: emscripten_build/libsolc/soljson.js
destination: soljson.js
- run: mkdir -p workspace
- run: cp build/libsolc/soljson.js workspace/soljson.js
- run: cp emscripten_build/libsolc/soljson.js workspace/soljson.js
- run: scripts/get_version.sh > workspace/version.txt
- persist_to_workspace:
root: workspace
@ -202,8 +202,6 @@ jobs:
- run:
name: Install build dependencies
command: |
brew update
brew upgrade
brew unlink python
brew install z3
brew install boost
@ -353,8 +351,6 @@ jobs:
- run:
name: Install dependencies
command: |
brew update
brew upgrade
brew unlink python
brew install z3
- run: mkdir -p test_results

1
.gitignore vendored
View File

@ -32,6 +32,7 @@ prerelease.txt
# Build directory
build/
emscripten_build/
docs/_build
docs/utils/__pycache__
docs/utils/*.pyc

View File

@ -10,7 +10,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.5.4")
set(PROJECT_VERSION "0.5.5")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES CXX)
option(LLL "Build LLL" OFF)

View File

@ -1,3 +1,43 @@
### 0.5.5 (2019-03-05)
Language Features:
* Add support for getters of mappings with ``string`` or ``bytes`` key types.
* Meta programming: Provide access to the name of contracts via ``type(C).name``.
Compiler Features:
* Support ``petersburg`` as ``evmVersion`` and set as default.
* Inline Assembly: Consider ``extcodehash`` as part of Constantinople.
* Inline Assembly: Instructions unavailable to the currently configured EVM are errors now.
* SMTChecker: Do not report underflow/overflow if they always revert. This removes false positives when using ``SafeMath``.
* Standard JSON Interface: Allow retrieving metadata without triggering bytecode generation.
* Static Analyzer: Warn about expressions with custom types when they have no effect.
* Optimizer: Add new rules with constants including ``LT``, ``GT``, ``AND`` and ``BYTE``.
* Optimizer: Add rule for shifts with constants for Constantinople.
* Optimizer: Combine multiple shifts with constant shift-by values into one.
* Optimizer: Do not mask with 160-bits after ``CREATE`` and ``CREATE2`` as they are guaranteed to return an address or 0.
* Optimizer: Support shifts in the constant optimiser for Constantinople.
* Yul Optimizer: Add rule to replace switch statements with literals by matching case body.
Bugfixes:
* ABIEncoderV2: Fix internal error related to bare delegatecall.
* ABIEncoderV2: Fix internal error related to ecrecover.
* ABIEncoderV2: Fix internal error related to mappings as library parameters.
* ABIEncoderV2: Fix invalid signature for events containing structs emitted in libraries.
* Inline Assembly: Proper error message for missing variables.
* Optimizer: Fix internal error related to unused tag removal across assemblies. This never generated any invalid code.
* SMTChecker: Fix crash related to statically-sized arrays.
* TypeChecker: Fix internal error and disallow index access on contracts and libraries.
* Yul: Properly detect name clashes with functions before their declaration.
* Yul: Take built-in functions into account in the compilability checker.
* Yul Optimizer: Properly take reassignments to variables in sub-expressions into account when replacing in the ExpressionSimplifier.
Build System:
* Soltest: Add support for left-aligned, padded hex literals.
* Soltest: Add support for right-aligned, padded boolean literals.
### 0.5.4 (2019-02-12)
Language Features:

View File

@ -1,24 +1,51 @@
Checklist for making a release:
## Checklist for making a release:
### Requirements
- [ ] Lauchpad (Ubuntu One) account
- [ ] gnupg key (has to be version 1, gpg2 won't work) for `your-name@ethereum.org` created and uploaded
- [ ] Readthedocs account, access to the Solidity project
- [ ] Write access to https://github.com/ethereum/homebrew-ethereum
### Pre-release
- [ ] Ensure that a Github project exists for the release.
- [ ] Check that all issues and pull requests from the Github project to be released are merged to ``develop``.
- [ ] Create a commit in ``develop`` that updates the ``Changelog`` to include a release date (run ``./scripts/tests.sh`` to update the bug list). Sort the changelog entries alphabetically and correct any errors you notice.
### Changelog
- [ ] Sort the changelog entries alphabetically and correct any errors you notice.
- [ ] Create a commit on a new branch that updates the ``Changelog`` to include a release date.
- [ ] Run ``./scripts/tests.sh`` to update the bug list.
- [ ] Create a pull request and wait for the tests, merge it.
### Create the Release
- [ ] Create Github release page: https://github.com/ethereum/solidity/releases/new
- [ ] On the release page, select the ``release`` branch as new target and set tag to the new version (e.g. `v0.5.4`) (make sure you only `SAVE DRAFT` instead of `PUBLISH RELEASE` before the actual release)
- [ ] Thank voluntary contributors in the Github release page (use ``git shortlog -s -n -e origin/release..origin/develop``).
- [ ] Create a pull request from ``develop`` to ``release``, wait for the tests, then merge it.
- [ ] Make a final check that there are no platform-dependency issues in the ``solidity-test-bytecode`` repository.
- [ ] Wait for the tests for the commit on ``release``, create a release in Github, creating the tag.
- [ ] Wait for the CI runs on the tag itself (they should push artifacts onto the Github release page).
- [ ] Run ``scripts/create_source_tarball.sh`` while being on the tag to create the source tarball.
- [ ] Upload the source tarball (in the upload directory) to the release page.
- [ ] Wait for the CI runs on the tag itself (travis and appveyor should push artifacts onto the Github release page).
- [ ] Run ``scripts/create_source_tarball.sh`` while being on the tag to create the source tarball. Make sure to create ``prerelease.txt`` before: (``echo -n > prerelease.txt``). This will create the tarball in a directory called ``upload``.
- [ ] Take the tarball from the upload directory (its name should be ``solidity_x.x.x.tar.gz``, otherwise ``prerelease.txt`` was missing in the step before) and upload the source tarball to the release page.
- [ ] Click the `PUBLISH RELEASE` button on the release page.
### PPA
- [ ] Change ``scripts/release_ppa.sh`` to match your key's email and key id.
- [ ] Run ``scripts/release_ppa.sh release`` to create the PPA release (you need the relevant openssl key).
- [ ] Once the ``~ethereum/ubuntu/ethereum-static`` PPA build is finished and published for all platforms (make sure not to do this earlier), copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` and ``Xenial`` while selecting ``Copy existing binaries``.
- [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh release``).
- [ ] Update the homebrew realease in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb (version and hash)
- [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` and ``Xenial`` while selecting ``Copy existing binaries``.
- [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh v0.x.x``).
### Homebrew
- [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb
### Documentation
- [ ] Update the default version on readthedocs.
- [ ] Make a release of ``solc-js``: Increment the version number, create a pull request for that, merge it after tests succeeded.
### Release solc-js
- [ ] Increment the version number, create a pull request for that, merge it after tests succeeded.
- [ ] Run ``npm publish`` in the updated ``solc-js`` repository.
- [ ] Create a commit to increase the version number on ``develop`` in ``CMakeLists.txt`` and add a new skeleton changelog entry.
- [ ] Merge ``release`` back into ``develop``.
### Post-release
- [ ] Announce on Twitter and Reddit.
- [ ] Lean back, wait for bug reports and repeat from step 1 :)

View File

@ -3,6 +3,10 @@ codecov:
coverage:
range: 70...100
status:
patch:
default:
target: "50%"
paths: "!test/"
project:
default:
target: auto

View File

@ -162,7 +162,6 @@ Note that the order of arguments can be seen to be reversed in non-functional st
Opcodes marked with ``-`` do not push an item onto the stack (do not return a result),
those marked with ``*`` are special and all others push exactly one item onto the stack (their "return value").
Opcodes marked with ``F``, ``H``, ``B`` or ``C`` are present since Frontier, Homestead, Byzantium or Constantinople, respectively.
Constantinople is still in planning and all instructions marked as such will result in an invalid instruction exception.
In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to
but not including position ``b`` and ``storage[p]`` signifies the storage contents at position ``p``.

View File

@ -628,5 +628,9 @@
"0.5.4": {
"bugs": [],
"released": "2019-02-12"
},
"0.5.5": {
"bugs": [],
"released": "2019-03-05"
}
}

View File

@ -90,7 +90,7 @@ The option ``--no-smt`` disables the tests that require ``libz3`` and
``--no-ipc`` disables those that require ``aleth``.
If you want to run the ipc tests (that test the semantics of the generated code),
you need to install `aleth <https://github.com/ethereum/aleth/releases/download/v1.5.0-alpha.7/aleth-1.5.0-alpha.7-linux-x86_64.tar.gz>`_ and run it in testing mode: ``aleth --db memorydb --test -d /tmp/testeth``.
you need to install `aleth <https://github.com/ethereum/aleth/releases/download/v1.5.2/aleth-1.5.2-linux-x86_64.tar.gz>`_ and run it in testing mode: ``aleth --db memorydb --test -d /tmp/testeth``.
To run the actual tests, use: ``./scripts/soltest.sh --ipcpath /tmp/testeth/geth.ipc``.
@ -326,3 +326,82 @@ escaping and without iterated replacements. An area can be delimited by ``<#name
by as many concatenations of its contents as there were sets of variables supplied to the template system,
each time replacing any ``<inner>`` items by their respective value. Top-level variables can also be used
inside such areas.
.. _documentation-style:
Documentation Style Guide
=========================
The following are style recommendations specifically for documentation
contributions to Solidity.
English Language
----------------
Use English, with British English spelling preferred, unless using project or brand names. Try to reduce the usage of
local slang and references, making your language as clear to all readers as possible. Below are some references to help:
* `Simplified technical English <https://en.wikipedia.org/wiki/Simplified_Technical_English>`_
* `International English <https://en.wikipedia.org/wiki/International_English>`_
* `British English spelling <https://en.oxforddictionaries.com/spelling/british-and-spelling>`_
.. note::
While the official Solidity documentation is written in English, there are community contributed :ref:`translations`
in other languages available.
Title Case for Headings
-----------------------
Use `title case <http://titlecase.com>`_ for headings. This means capitalise all principal words in
titles, but not articles, conjunctions, and prepositions unless they start the
title.
For example, the following are all correct:
* Title Case for Headings
* For Headings Use Title Case
* Local and State Variable Names
* Order of Layout
Expand Contractions
-------------------
Use expanded contractions for words, for example:
* "Do not" instead of "Don't".
* "Can not" instead of "Can't".
Active and Passive Voice
------------------------
Active voice is typically recommended for tutorial style documentation as it
helps the reader understand who or what is performing a task. However, as the
Solidity documentation is a mixture of tutorials and reference content, passive
voice is sometimes more applicable.
As a summary:
* Use passive voice for technical reference, for example language definition and internals of the Ethereum VM.
* Use active voice when describing recommendations on how to apply an aspect of Solidity.
For example, the below is in passive voice as it specifies an aspect of Solidity:
Functions can be declared ``pure`` in which case they promise not to read
from or modify the state.
For example, the below is in active voice as it discusses an application of Solidity:
When invoking the compiler, you can specify how to discover the first element
of a path, and also path prefix remappings.
Common Terms
------------
* "Function parameters" and "return variables", not input and output parameters.
Code Examples
-------------
* Ensure that all code examples begin with a ``pragma`` version that spans the largest where the contract code is valid. For example ``pragma solidity >=0.4.0 <0.6.0;``.

View File

@ -91,7 +91,7 @@ You need to use the modifier ``payable`` with the ``info`` function because
otherwise, the ``.value()`` option would not be available.
.. warning::
Be careful that ``feed.info.value(10).gas(800)`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the parentheses at the end perform the actual call. So in this case, the function is not called.
Be careful that ``feed.info.value(10).gas(800)`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the parentheses at the end perform the actual call. So in this case, the function is not called and the ``value`` and ``gas`` settings are lost.
Function calls cause exceptions if the called contract does not exist (in the
sense that the account does not contain code) or if the called contract itself

57
docs/examples/modular.rst Normal file
View File

@ -0,0 +1,57 @@
.. index:: contract;modular, modular contract
*****************
Modular Contracts
*****************
A modular approach to building your contracts helps you prevent overflow risks
and unexpected tokens. In the example below, the contract uses the ``move`` method
of the ``Balances`` :ref:`library <libraries>` to check that balances sent between
addresses match what you expect.
::
pragma solidity >=0.4.22 <0.6.0;
library Balances {
function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal {
require(balances[from] >= amount);
require(balances[to] + amount >= balances[to]);
balances[from] -= amount;
balances[to] += amount;
}
}
contract Token {
mapping(address => uint256) balances;
using Balances for *;
mapping(address => mapping (address => uint256)) allowed;
event Transfer(address from, address to, uint amount);
event Approval(address owner, address spender, uint amount);
function balanceOf(address tokenOwner) public view returns (uint balance) {
return balances[tokenOwner];
}
function transfer(address to, uint amount) public returns (bool success) {
balances.move(msg.sender, to, amount);
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(address from, address to, uint amount) public returns (bool success) {
require(allowed[from][msg.sender] >= amount);
allowed[from][msg.sender] -= amount;
balances.move(from, to, amount);
emit Transfer(from, to, amount);
return true;
}
function approve(address spender, uint tokens) public returns (bool success) {
require(allowed[msg.sender][spender] == 0, "");
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
}

View File

@ -19,7 +19,7 @@ user-defined types among other features.
With Solidity you can create contracts for uses such as voting, crowdfunding, blind auctions,
and multi-signature wallets.
When deploying contracts, you should use the latest released version of Solidity. This is because breaking changes as well as new features and bug fixes are introduced regularly. We currently use a 0.x version number [to indicate this fast pace of change](https://semver.org/#spec-item-4).
When deploying contracts, you should use the latest released version of Solidity. This is because breaking changes as well as new features and bug fixes are introduced regularly. We currently use a 0.x version number `to indicate this fast pace of change <https://semver.org/#spec-item-4>`_.
Language Documentation
----------------------
@ -52,6 +52,8 @@ If you have any questions, you can try searching for answers or asking on the
Ideas for improving Solidity or this documentation are always welcome, read our :doc:`contributors guide <contributing>` for more details.
.. _translations:
Translations
------------

View File

@ -154,23 +154,35 @@ Gentoo Linux also provides a solidity package that can be installed using ``emer
Building from Source
====================
Prerequisites - Linux
---------------------
Prerequisites - All Operating Systems
-------------------------------------
You need to install the following dependencies for Linux builds of Solidity:
The following are dependencies for all builds of Solidity:
+-----------------------------------+-------------------------------------------------------+
| Software | Notes |
+===================================+=======================================================+
| `Git for Linux`_ | Command-line tool for retrieving source from Github. |
| `CMake`_ | Cross-platform build file generator. |
+-----------------------------------+-------------------------------------------------------+
| `Boost`_ (version 1.65+) | C++ libraries. |
+-----------------------------------+-------------------------------------------------------+
| `Git`_ | Command-line tool for retrieving source code. |
+-----------------------------------+-------------------------------------------------------+
| `z3`_ (version 5.6+, Optional) | For use with SMT checker. |
+-----------------------------------+-------------------------------------------------------+
| `cvc4`_ (Optional) | For use with SMT checker. |
+-----------------------------------+-------------------------------------------------------+
.. _Git for Linux: https://git-scm.com/download/linux
.. _cvc4: http://cvc4.cs.stanford.edu/web/
.. _Git: https://git-scm.com/download
.. _Boost: https://www.boost.org
.. _CMake: https://cmake.org/download/
.. _z3: https://github.com/Z3Prover/z3
Prerequisites - macOS
---------------------
For macOS, ensure that you have the latest version of
For macOS builds, ensure that you have the latest version of
`Xcode installed <https://developer.apple.com/xcode/download/>`_.
This contains the `Clang C++ compiler <https://en.wikipedia.org/wiki/Clang>`_, the
`Xcode IDE <https://en.wikipedia.org/wiki/Xcode>`_ and other Apple development
@ -183,13 +195,12 @@ command-line builds:
sudo xcodebuild -license accept
Our OS X builds require you to `install the Homebrew <http://brew.sh>`_
Our OS X build script uses `the Homebrew <http://brew.sh>`_
package manager for installing external dependencies.
Here's how to `uninstall Homebrew
<https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/FAQ.md#how-do-i-uninstall-homebrew>`_,
if you ever want to start again from scratch.
Prerequisites - Windows
-----------------------
@ -198,21 +209,17 @@ You need to install the following dependencies for Windows builds of Solidity:
+-----------------------------------+-------------------------------------------------------+
| Software | Notes |
+===================================+=======================================================+
| `Git for Windows`_ | Command-line tool for retrieving source from Github. |
+-----------------------------------+-------------------------------------------------------+
| `CMake`_ | Cross-platform build file generator. |
+-----------------------------------+-------------------------------------------------------+
| `Visual Studio 2017 Build Tools`_ | C++ compiler |
+-----------------------------------+-------------------------------------------------------+
| `Visual Studio 2017`_ (Optional) | C++ compiler and dev environment. |
+-----------------------------------+-------------------------------------------------------+
If you've already had one IDE and only need compiler and libraries,
If you already have one IDE and only need the compiler and libraries,
you could install Visual Studio 2017 Build Tools.
Visual Studio 2017 provides both IDE and necessary compiler and libraries.
So if you have not got an IDE and prefer to develop solidity, Visual Studio 2017
may be an choice for you to get everything setup easily.
may be a choice for you to get everything setup easily.
Here is the list of components that should be installed
in Visual Studio 2017 Build Tools or Visual Studio 2017:
@ -223,11 +230,25 @@ in Visual Studio 2017 Build Tools or Visual Studio 2017:
* Windows 8.1 SDK
* C++/CLI support
.. _Git for Windows: https://git-scm.com/download/win
.. _CMake: https://cmake.org/download/
.. _Visual Studio 2017: https://www.visualstudio.com/vs/
.. _Visual Studio 2017 Build Tools: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017
Dependencies Helper Script
--------------------------
We have a helper script which you can use to install all required external dependencies
on macOS, Windows and on numerous Linux distros.
.. code-block:: bash
./scripts/install_deps.sh
Or, on Windows:
.. code-block:: bat
scripts\install_deps.bat
Clone the Repository
--------------------
@ -245,23 +266,6 @@ you should fork Solidity and add your personal fork as a second remote:
git remote add personal git@github.com:[username]/solidity.git
External Dependencies
---------------------
We have a helper script which installs all required external dependencies
on macOS, Windows and on numerous Linux distros.
.. code-block:: bash
./scripts/install_deps.sh
Or, on Windows:
.. code-block:: bat
scripts\install_deps.bat
Command-Line Build
------------------
@ -278,7 +282,11 @@ Building Solidity is quite similar on Linux, macOS and other Unices:
cd build
cmake .. && make
or even easier:
.. warning::
BSD builds should work, but are untested by the Solidity team.
or even easier on Linux and macOS, you can run:
.. code-block:: bash

View File

@ -66,10 +66,23 @@ explanatory purposes.
{
// Required for Solidity: Sorted list of remappings
remappings: [ ":g/dir" ],
// Optional: Optimizer settings (enabled defaults to false)
// Optional: Optimizer settings. The fields "enabled" and "runs" are deprecated
// and are only given for backwards-compatibility.
optimizer: {
enabled: true,
runs: 500
runs: 500,
details: {
// peephole defaults to "true"
peephole: true,
// jumpdestRemover defaults to "true"
jumpdestRemover: true,
orderLiterals: false,
deduplicate: false,
cse: false,
constantOptimizer: false,
yul: false,
yulDetails: {}
}
},
// Required for Solidity: File and name of the contract or library this
// metadata is created for.

View File

@ -385,6 +385,7 @@ Global Variables
- ``<address>.balance`` (``uint256``): balance of the :ref:`address` in Wei
- ``<address payable>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure
- ``<address payable>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
- ``type(C).name`` (``string``): the name of the contract
- ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information<meta-type>`.
- ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information<meta-type>`.

View File

@ -3,8 +3,11 @@ Solidity by Example
###################
.. include:: examples/voting.rst
.. include:: examples/blind-auction.rst
.. include:: examples/safe-remote.rst
.. include:: examples/micropayment.rst
.. include:: examples/micropayment.rst
.. include:: examples/modular.rst

View File

@ -1088,12 +1088,6 @@ Avoiding Naming Collisions
This convention is suggested when the desired name collides with that of a
built-in or otherwise reserved name.
General Recommendations
=======================
TODO
.. _natspec:
*******

View File

@ -305,8 +305,7 @@ Contract Types
Every :ref:`contract<contracts>` defines its own type.
You can implicitly convert contracts to contracts they inherit from.
Contracts can be explicitly converted to and from all other contract types
and the ``address`` type.
Contracts can be explicitly converted to and from the ``address`` type.
Explicit conversion to and from the ``address payable`` type
is only possible if the contract type has a payable fallback function.
@ -614,15 +613,23 @@ just use ``f``, if you want to use its external form, use ``this.f``.
Members:
Public (or external) functions also have a special member called ``selector``,
which returns the :ref:`ABI function selector <abi_function_selector>`::
Public (or external) functions have the following members:
* ``.selector`` returns the :ref:`ABI function selector <abi_function_selector>`
* ``.gas(uint)`` returns a callable function object which, when called, will send the specified amount of gas to the target function. See :ref:`External Function Calls <external-function-calls>` for more information.
* ``.value(uint)`` returns a callable function object which, when called, will send the specified amount of wei to the target function. See :ref:`External Function Calls <external-function-calls>` for more information.
Example that shows how to use the members::
pragma solidity >=0.4.16 <0.6.0;
contract Selector {
function f() public pure returns (bytes4) {
contract Example {
function f() public payable returns (bytes4) {
return this.f.selector;
}
function g() public {
this.f.gas(10).value(800)();
}
}
Example that shows how to use internal function types::

View File

@ -156,29 +156,41 @@ Mathematical and Cryptographic Functions
``addmod(uint x, uint y, uint k) returns (uint)``:
compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0.
``mulmod(uint x, uint y, uint k) returns (uint)``:
compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0.
``keccak256(bytes memory) returns (bytes32)``:
compute the Keccak-256 hash of the input
``sha256(bytes memory) returns (bytes32)``:
compute the SHA-256 hash of the input
``ripemd160(bytes memory) returns (bytes20)``:
compute RIPEMD-160 hash of the input
``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``:
recover the address associated with the public key from elliptic curve signature or return zero on error
(`example usage <https://ethereum.stackexchange.com/q/1777/222>`_)
recover the address associated with the public key from elliptic curve signature or return zero on error.
The function parameters correspond to ECDSA values of the signature:
``r`` = first 32 bytes of signature
``s`` = second 32 bytes of signature
``v`` = final 1 byte of signature
``ecrecover`` returns an ``address``, and not an ``address payable``. See :ref:`address payable<address>` for
conversion, in case you need to transfer funds to the recovered address.
For further details, read `example usage <https://ethereum.stackexchange.com/q/1777/222>`_.
.. note::
Function ``ecrecover`` returns an ``address``, and not an ``address
payable``. See :ref:`address payable<address>` for conversion, in case you need
to transfer funds to the recovered address.
It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net.
When running ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*, you might encounter Out-of-Gas. This is because these functions are implemented as "precompiled contracts" and only really exist after they receive the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution might run into an Out-of-Gas error. A workaround for this problem is to first send Wei (1 for example) to each of the contracts before you use them in your actual contracts. This is not an issue on the main or test net.
.. note::
There used to be an alias for ``keccak256`` called ``sha3``, which was removed in version 0.5.0.
.. index:: balance, send, transfer, call, callcode, delegatecall, staticcall
.. _address_related:
Members of Address Types
@ -257,6 +269,9 @@ type ``X``. Currently, there is limited support for this feature, but
it might be expanded in the future. The following properties are
available for a contract type ``C``:
``type(C).name``:
The name of the contract.
``type(C).creationCode``:
Memory byte array that contains the creation bytecode of the contract.
This can be used in inline assembly to build custom creation routines,

View File

@ -17,10 +17,15 @@ Using ``solc --help`` provides you with an explanation of all options. The compi
If you only want to compile a single file, you run it as ``solc --bin sourceFile.sol`` and it will print the binary. If you want to get some of the more advanced output variants of ``solc``, it is probably better to tell it to output everything to separate files using ``solc -o outputDirectory --bin --ast --asm sourceFile.sol``.
Before you deploy your contract, activate the optimizer when compiling using ``solc --optimize --bin sourceFile.sol``.
By default, the optimizer will optimize the contract assuming it is called 200 times across its lifetime.
By default, the optimizer will optimize the contract assuming it is called 200 times across its lifetime
(more specifically, it assumes each opcode is executed around 200 times).
If you want the initial contract deployment to be cheaper and the later function executions to be more expensive,
set it to ``--optimize-runs=1``. If you expect many transactions and do not care for higher deployment cost and
output size, set ``--optimize-runs`` to a high number.
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
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:
@ -103,18 +108,21 @@ at each version. Backward compatibility is not guaranteed between each version.
- ``homestead`` (oldest version)
- ``tangerineWhistle``
- gas cost for access to other accounts increased, relevant for gas estimation and the optimizer.
- all gas sent by default for external calls, previously a certain amount had to be retained.
- Gas cost for access to other accounts increased, relevant for gas estimation and the optimizer.
- All gas sent by default for external calls, previously a certain amount had to be retained.
- ``spuriousDragon``
- gas cost for the ``exp`` opcode increased, relevant for gas estimation and the optimizer.
- ``byzantium`` (**default**)
- opcodes ``returndatacopy``, ``returndatasize`` and ``staticcall`` are available in assembly.
- the ``staticcall`` opcode is used when calling non-library view or pure functions, which prevents the functions from modifying state at the EVM level, i.e., even applies when you use invalid type conversions.
- it is possible to access dynamic data returned from function calls.
- Gas cost for the ``exp`` opcode increased, relevant for gas estimation and the optimizer.
- ``byzantium``
- Opcodes ``returndatacopy``, ``returndatasize`` and ``staticcall`` are available in assembly.
- The ``staticcall`` opcode is used when calling non-library view or pure functions, which prevents the functions from modifying state at the EVM level, i.e., even applies when you use invalid type conversions.
- It is possible to access dynamic data returned from function calls.
- ``revert`` opcode introduced, which means that ``revert()`` will not waste gas.
- ``constantinople`` (still in progress)
- opcodes ``shl``, ``shr`` and ``sar`` are available in assembly.
- shifting operators use shifting opcodes and thus need less gas.
- ``constantinople``
- Opcodes ``create2`, ``extcodehash``, ``shl``, ``shr`` and ``sar`` are available in assembly.
- Shifting operators use shifting opcodes and thus need less gas.
- ``petersburg`` (**default**)
- The compiler behaves the same way as with constantinople.
.. _compiler-api:
@ -186,9 +194,33 @@ Input Description
"enabled": true,
// Optimize for how many times you intend to run the code.
// Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage.
"runs": 200
"runs": 200,
// Switch optimizer components on or off in detail.
// The "enabled" switch above provides two defaults which can be
// tweaked here. If "details" is given, "enabled" can be omitted.
"details": {
// The peephole optimizer is always on if no details are given, use details to switch it off.
"peephole": true,
// The unused jumpdest remover is always on if no details are given, use details to switch it off.
"jumpdestRemover": true,
// Sometimes re-orders literals in commutative operations.
"orderLiterals": false,
// Removes duplicate code blocks
"deduplicate": false,
// Common subexpression elimination, this is the most complicated step but
// can also provide the largest gain.
"cse": false,
// Optimize representation of literal numbers and strings in code.
"constantOptimizer": false,
// The new Yul optimizer. Mostly operates on the code of ABIEncoderV2.
// It can only be activated through the details here.
// This feature is still considered experimental.
"yul": false,
// Future tuning options, currently unused.
"yulDetails": {}
}
},
"evmVersion": "byzantium", // Version of the EVM to compile for. Affects type checking and code generation. Can be homestead, tangerineWhistle, spuriousDragon, byzantium or constantinople
"evmVersion": "byzantium", // Version of the EVM to compile for. Affects type checking and code generation. Can be homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople or petersburg
// Metadata settings (optional)
"metadata": {
// Use only literal content and not URLs (false by default)

View File

@ -74,7 +74,7 @@ using strings = std::vector<std::string>;
/// Interprets @a _u as a two's complement signed number and returns the resulting s256.
inline s256 u2s(u256 _u)
{
static const bigint c_end = bigint(1) << 256;
static bigint const c_end = bigint(1) << 256;
if (boost::multiprecision::bit_test(_u, 255))
return s256(-(c_end - _u));
else
@ -84,10 +84,10 @@ inline s256 u2s(u256 _u)
/// @returns the two's complement signed representation of the signed number _u.
inline u256 s2u(s256 _u)
{
static const bigint c_end = bigint(1) << 256;
if (_u >= 0)
static bigint const c_end = bigint(1) << 256;
if (_u >= 0)
return u256(_u);
else
else
return u256(c_end + _u);
}

View File

@ -140,6 +140,12 @@ inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0)
return (_min || _val) ? bytes{ _val } : bytes{};
}
/// Workarounds shift left bug in boost <1.65.1.
template <class S> S bigintShiftLeftWorkaround(S const& _a, unsigned _b)
{
return (S)(bigint(_a) << _b);
}
/// Convenience function for conversion of a u256 to hex
inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd)
{
@ -175,9 +181,6 @@ inline std::string toCompactHexWithPrefix(u256 val)
// Algorithms for string and string-like collections.
/// Escapes a string into the C-string representation.
/// @p _all if true will escape all characters, not just the unprintable ones.
std::string escaped(std::string const& _s, bool _all = true);
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class T>
inline unsigned bytesRequired(T _i)
@ -240,7 +243,7 @@ bool contains(T const& _t, V const& _v)
/// place at the end, but already visited elements might be invalidated.
/// If nothing is replaced, no copy is performed.
template <typename T, typename F>
void iterateReplacing(std::vector<T>& _vector, const F& _f)
void iterateReplacing(std::vector<T>& _vector, F const& _f)
{
// Concept: _f must be Callable, must accept param T&, must return optional<vector<T>>
bool useModified = false;

View File

@ -31,7 +31,7 @@ namespace dev
/// Base class for all exceptions.
struct Exception: virtual std::exception, virtual boost::exception
{
const char* what() const noexcept override;
char const* what() const noexcept override;
/// @returns "FileName:LineNumber" referring to the point where the exception was thrown.
std::string lineInfo() const;

View File

@ -47,17 +47,17 @@ namespace
/******** The Keccak-f[1600] permutation ********/
/*** Constants. ***/
static const uint8_t rho[24] = \
static uint8_t const rho[24] = \
{ 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \
static uint8_t const pi[24] = \
{10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2,
20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \
static uint64_t const RC[24] = \
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
@ -71,8 +71,8 @@ static const uint64_t RC[24] = \
#define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e
#define FOR5(v, s, e) \
v = 0; \
REPEAT5(e; v += s;)
v = 0; \
REPEAT5(e; v += s;)
/*** Keccak-f[1600] ***/
static inline void keccakf(void* state) {
@ -84,25 +84,25 @@ static inline void keccakf(void* state) {
uint8_t x, y;
// Theta
FOR5(x, 1,
b[x] = 0;
FOR5(y, 5,
b[x] ^= a[x + y]; ))
b[x] = 0;
FOR5(y, 5,
b[x] ^= a[x + y]; ))
FOR5(x, 1,
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi
uint64_t t = a[1];
x = 0;
REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]);
t = b[0];
x++; )
a[pi[x]] = rol(t, rho[x]);
t = b[0];
x++; )
// Chi
FOR5(y,
5,
FOR5(x, 1,
5,
FOR5(x, 1,
b[x] = a[y + x];)
FOR5(x, 1,
FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// Iota
a[0] ^= RC[i];
@ -115,19 +115,19 @@ static inline void keccakf(void* state) {
#define _(S) do { S } while (0)
#define FOR(i, ST, L, S) \
_(for (size_t i = 0; i < L; i += ST) { S; })
_(for (size_t i = 0; i < L; i += ST) { S; })
#define mkapply_ds(NAME, S) \
static inline void NAME(uint8_t* dst, \
const uint8_t* src, \
size_t len) { \
FOR(i, 1, len, S); \
}
static inline void NAME(uint8_t* dst, \
uint8_t const* src, \
size_t len) { \
FOR(i, 1, len, S); \
}
#define mkapply_sd(NAME, S) \
static inline void NAME(const uint8_t* src, \
uint8_t* dst, \
size_t len) { \
FOR(i, 1, len, S); \
}
static inline void NAME(uint8_t const* src, \
uint8_t* dst, \
size_t len) { \
FOR(i, 1, len, S); \
}
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
mkapply_sd(setout, dst[i] = src[i]) // setout
@ -137,18 +137,18 @@ mkapply_sd(setout, dst[i] = src[i]) // setout
// Fold P*F over the full blocks of an input.
#define foldP(I, L, F) \
while (L >= rate) { \
F(a, I, rate); \
P(a); \
I += rate; \
L -= rate; \
}
while (L >= rate) { \
F(a, I, rate); \
P(a); \
I += rate; \
L -= rate; \
}
/** The sponge-based hash construction. **/
inline void hash(
uint8_t* out,
size_t outlen,
const uint8_t* in,
uint8_t const* in,
size_t inlen,
size_t rate,
uint8_t delim

View File

@ -139,8 +139,8 @@ inline std::string formatNumberReadable(
if (len < 24)
return str;
const int initialChars = (prefix == HexPrefix::Add) ? 6 : 4;
const int finalChars = 4;
int const initialChars = (prefix == HexPrefix::Add) ? 6 : 4;
int const finalChars = 4;
int numSkipped = len - initialChars - finalChars;
return str.substr(0, initialChars) +

View File

@ -77,7 +77,7 @@ bool isWellFormed(unsigned char byte1, unsigned char byte2)
return false;
}
bool validateUTF8(const unsigned char *_input, size_t _length, size_t& _invalidPosition)
bool validateUTF8(unsigned char const* _input, size_t _length, size_t& _invalidPosition)
{
bool valid = true;
size_t i = 0;

View File

@ -390,7 +390,7 @@ Assembly& Assembly::optimise(OptimiserSettings const& _settings)
map<u256, u256> Assembly::optimiseInternal(
OptimiserSettings const& _settings,
std::set<size_t> const& _tagsReferencedFromOutside
std::set<size_t> _tagsReferencedFromOutside
)
{
// Run optimisation for sub-assemblies.
@ -436,7 +436,22 @@ map<u256, u256> Assembly::optimiseInternal(
BlockDeduplicator dedup{m_items};
if (dedup.deduplicate())
{
tagReplacements.insert(dedup.replacedTags().begin(), dedup.replacedTags().end());
for (auto const& replacement: dedup.replacedTags())
{
assertThrow(
replacement.first <= size_t(-1) && replacement.second <= size_t(-1),
OptimizerException,
"Invalid tag replacement."
);
assertThrow(
!tagReplacements.count(replacement.first),
OptimizerException,
"Replacement already known."
);
tagReplacements[replacement.first] = replacement.second;
if (_tagsReferencedFromOutside.erase(size_t(replacement.first)))
_tagsReferencedFromOutside.insert(size_t(replacement.second));
}
count++;
}
}

View File

@ -107,13 +107,14 @@ public:
bool runDeduplicate = false;
bool runCSE = false;
bool runConstantOptimiser = false;
solidity::EVMVersion evmVersion;
langutil::EVMVersion evmVersion;
/// This specifies an estimate on how often each opcode in this assembly will be executed,
/// i.e. use a small value to optimise for size and a large value to optimise for runtime gas usage.
size_t expectedExecutionsPerDeployment = 200;
};
/// Execute optimisation passes as defined by @a _settings and return the optimised assembly.
/// Modify and return the current assembly such that creation and execution gas usage
/// is optimised according to the settings in @a _settings.
Assembly& optimise(OptimiserSettings const& _settings);
/// Modify (if @a _enable is set) and return the current assembly such that creation and
@ -121,7 +122,7 @@ public:
/// @a _runs specifes an estimate on how often each opcode in this assembly will be executed,
/// i.e. use a small value to optimise for size and a large value to optimise for runtime.
/// If @a _enable is not set, will perform some simple peephole optimizations.
Assembly& optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation = true, size_t _runs = 200);
Assembly& optimise(bool _enable, langutil::EVMVersion _evmVersion, bool _isCreation, size_t _runs);
/// Create a text representation of the assembly.
std::string assemblyString(
@ -154,7 +155,7 @@ protected:
/// Does the same operations as @a optimise, but should only be applied to a sub and
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
/// that are referenced in a super-assembly.
std::map<u256, u256> optimiseInternal(OptimiserSettings const& _settings, std::set<size_t> const& _tagsReferencedFromOutside);
std::map<u256, u256> optimiseInternal(OptimiserSettings const& _settings, std::set<size_t> _tagsReferencedFromOutside);
unsigned bytesRequired(unsigned subTagSize) const;

View File

@ -149,7 +149,7 @@ private:
/// Appends the given assembly item.
void appendItem(AssemblyItem const& _item);
static const int c_invalidPosition = -0x7fffffff;
static int const c_invalidPosition = -0x7fffffff;
AssemblyItems m_generatedItems;
/// Current height of the stack relative to the start.
@ -161,7 +161,7 @@ private:
/// Current positions of equivalence classes, equal to the empty set if already deleted.
std::map<Id, std::set<int>> m_classPositions;
/// The actual eqivalence class items and how to compute them.
/// The actual equivalence class items and how to compute them.
ExpressionClasses& m_expressionClasses;
/// Keeps information about which storage or memory slots were written to by which operations.
/// The operations are sorted ascendingly by sequence number.

View File

@ -29,7 +29,7 @@ using namespace dev::eth;
unsigned ConstantOptimisationMethod::optimiseConstants(
bool _isCreation,
size_t _runs,
solidity::EVMVersion _evmVersion,
langutil::EVMVersion _evmVersion,
Assembly& _assembly
)
{
@ -210,7 +210,10 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
AssemblyItems newRoutine;
if (lowerPart != 0)
newRoutine += findRepresentation(u256(abs(lowerPart)));
newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP};
if (m_params.evmVersion.hasBitwiseShifting())
newRoutine += AssemblyItems{u256(1), u256(bits), Instruction::SHL};
else
newRoutine += AssemblyItems{u256(bits), u256(2), Instruction::EXP};
if (upperPart != 1)
newRoutine += findRepresentation(upperPart) + AssemblyItems{Instruction::MUL};
if (lowerPart > 0)
@ -231,7 +234,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value)
}
}
bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine)
bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const
{
// This is a tiny EVM that can only evaluate some instructions.
vector<u256> stack;
@ -263,6 +266,24 @@ bool ComputeMethod::checkRepresentation(u256 const& _value, AssemblyItems const&
case Instruction::NOT:
sp[0] = ~sp[0];
break;
case Instruction::SHL:
assertThrow(
m_params.evmVersion.hasBitwiseShifting(),
OptimizerException,
"Shift generated for invalid EVM version."
);
assertThrow(sp[0] <= u256(255), OptimizerException, "Invalid shift generated.");
sp[-1] = u256(bigint(sp[-1]) << unsigned(sp[0]));
break;
case Instruction::SHR:
assertThrow(
m_params.evmVersion.hasBitwiseShifting(),
OptimizerException,
"Shift generated for invalid EVM version."
);
assertThrow(sp[0] <= u256(255), OptimizerException, "Invalid shift generated.");
sp[-1] = sp[-1] >> unsigned(sp[0]);
break;
default:
return false;
}

View File

@ -52,7 +52,7 @@ public:
static unsigned optimiseConstants(
bool _isCreation,
size_t _runs,
solidity::EVMVersion _evmVersion,
langutil::EVMVersion _evmVersion,
Assembly& _assembly
);
@ -64,7 +64,7 @@ protected:
bool isCreation; ///< Whether this is called during contract creation or runtime.
size_t runs; ///< Estimated number of calls per opcode oven the lifetime of the contract.
size_t multiplicity; ///< Number of times the constant appears in the code.
solidity::EVMVersion evmVersion; ///< Version of the EVM
langutil::EVMVersion evmVersion; ///< Version of the EVM
};
explicit ConstantOptimisationMethod(Params const& _params, u256 const& _value):
@ -155,7 +155,7 @@ protected:
/// Tries to recursively find a way to compute @a _value.
AssemblyItems findRepresentation(u256 const& _value);
/// Recomputes the value from the calculated representation and checks for correctness.
static bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine);
bool checkRepresentation(u256 const& _value, AssemblyItems const& _routine) const;
bigint gasNeeded(AssemblyItems const& _routine) const;
/// Counter for the complexity of optimization, will stop when it reaches zero.

View File

@ -47,24 +47,24 @@ namespace GasCosts
static unsigned const tier5Gas = 10;
static unsigned const tier6Gas = 20;
static unsigned const tier7Gas = 0;
inline unsigned extCodeGas(EVMVersion _evmVersion)
inline unsigned extCodeGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= EVMVersion::tangerineWhistle() ? 700 : 20;
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 700 : 20;
}
inline unsigned balanceGas(EVMVersion _evmVersion)
inline unsigned balanceGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= EVMVersion::tangerineWhistle() ? 400 : 20;
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 400 : 20;
}
static unsigned const expGas = 10;
inline unsigned expByteGas(EVMVersion _evmVersion)
inline unsigned expByteGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= EVMVersion::spuriousDragon() ? 50 : 10;
return _evmVersion >= langutil::EVMVersion::spuriousDragon() ? 50 : 10;
}
static unsigned const keccak256Gas = 30;
static unsigned const keccak256WordGas = 6;
inline unsigned sloadGas(EVMVersion _evmVersion)
inline unsigned sloadGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= EVMVersion::tangerineWhistle() ? 200 : 50;
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 200 : 50;
}
static unsigned const sstoreSetGas = 20000;
static unsigned const sstoreResetGas = 5000;
@ -74,16 +74,16 @@ namespace GasCosts
static unsigned const logDataGas = 8;
static unsigned const logTopicGas = 375;
static unsigned const createGas = 32000;
inline unsigned callGas(EVMVersion _evmVersion)
inline unsigned callGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= EVMVersion::tangerineWhistle() ? 700 : 40;
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 700 : 40;
}
static unsigned const callStipend = 2300;
static unsigned const callValueTransferGas = 9000;
static unsigned const callNewAccountGas = 25000;
inline unsigned selfdestructGas(EVMVersion _evmVersion)
inline unsigned selfdestructGas(langutil::EVMVersion _evmVersion)
{
return _evmVersion >= EVMVersion::tangerineWhistle() ? 5000 : 0;
return _evmVersion >= langutil::EVMVersion::tangerineWhistle() ? 5000 : 0;
}
static unsigned const selfdestructRefundGas = 24000;
static unsigned const memoryGas = 3;
@ -122,7 +122,7 @@ public:
};
/// Constructs a new gas meter given the current state.
GasMeter(std::shared_ptr<KnownState> const& _state, solidity::EVMVersion _evmVersion, u256 const& _largestMemoryAccess = 0):
GasMeter(std::shared_ptr<KnownState> const& _state, langutil::EVMVersion _evmVersion, u256 const& _largestMemoryAccess = 0):
m_state(_state), m_evmVersion(_evmVersion), m_largestMemoryAccess(_largestMemoryAccess) {}
/// @returns an upper bound on the gas consumed by the given instruction and updates
@ -152,7 +152,7 @@ private:
GasConsumption memoryGas(int _stackPosOffset, int _stackPosSize);
std::shared_ptr<KnownState> m_state;
EVMVersion m_evmVersion;
langutil::EVMVersion m_evmVersion;
/// Largest point where memory was accessed since the creation of this object.
u256 m_largestMemoryAccess;
};

View File

@ -29,7 +29,7 @@ using namespace std;
using namespace dev;
using namespace dev::solidity;
const std::map<std::string, Instruction> dev::solidity::c_instructions =
std::map<std::string, Instruction> const dev::solidity::c_instructions =
{
{ "STOP", Instruction::STOP },
{ "ADD", Instruction::ADD },
@ -173,7 +173,7 @@ const std::map<std::string, Instruction> dev::solidity::c_instructions =
{ "SELFDESTRUCT", Instruction::SELFDESTRUCT }
};
static const std::map<Instruction, InstructionInfo> c_instructionInfo =
static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ // Add, Args, Ret, SideEffects, GasPriceTier
{ Instruction::STOP, { "STOP", 0, 0, 0, true, Tier::Zero } },
{ Instruction::ADD, { "ADD", 0, 2, 1, false, Tier::VeryLow } },

View File

@ -27,7 +27,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
PathGasMeter::PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion):
PathGasMeter::PathGasMeter(AssemblyItems const& _items, langutil::EVMVersion _evmVersion):
m_items(_items), m_evmVersion(_evmVersion)
{
for (size_t i = 0; i < m_items.size(); ++i)

View File

@ -53,13 +53,13 @@ struct GasPath
class PathGasMeter
{
public:
explicit PathGasMeter(AssemblyItems const& _items, solidity::EVMVersion _evmVersion);
explicit PathGasMeter(AssemblyItems const& _items, langutil::EVMVersion _evmVersion);
GasMeter::GasConsumption estimateMax(size_t _startIndex, std::shared_ptr<KnownState> const& _state);
static GasMeter::GasConsumption estimateMax(
AssemblyItems const& _items,
solidity::EVMVersion _evmVersion,
langutil::EVMVersion _evmVersion,
size_t _startIndex,
std::shared_ptr<KnownState> const& _state
)
@ -81,7 +81,7 @@ private:
std::map<size_t, GasMeter::GasConsumption> m_highestGasUsagePerJumpdest;
std::map<u256, size_t> m_tagPositions;
AssemblyItems const& m_items;
solidity::EVMVersion m_evmVersion;
langutil::EVMVersion m_evmVersion;
};
}

View File

@ -24,6 +24,8 @@
#include <vector>
#include <functional>
#include <boost/multiprecision/detail/min_max.hpp>
#include <libevmasm/Instruction.h>
#include <libevmasm/SimplificationRule.h>
@ -85,12 +87,12 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart1(
return B.d();
unsigned testBit = unsigned(A.d()) * 8 + 7;
u256 mask = (u256(1) << testBit) - 1;
return u256(boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask);
return boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask;
}, false},
{{Instruction::SHL, {A, B}}, [=]{
if (A.d() > 255)
return u256(0);
return u256(bigint(B.d()) << unsigned(A.d()));
return bigintShiftLeftWorkaround(B.d(), unsigned(A.d()));
}, false},
{{Instruction::SHR, {A, B}}, [=]{
if (A.d() > 255)
@ -106,7 +108,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2(
Pattern,
Pattern,
Pattern X,
Pattern
Pattern Y
)
{
return std::vector<SimplificationRule<Pattern>> {
@ -140,6 +142,16 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2(
{{Instruction::MOD, {0, X}}, [=]{ return u256(0); }, true},
{{Instruction::EQ, {X, 0}}, [=]() -> Pattern { return {Instruction::ISZERO, {X}}; }, false },
{{Instruction::EQ, {0, X}}, [=]() -> Pattern { return {Instruction::ISZERO, {X}}; }, false },
{{Instruction::SHL, {0, X}}, [=]{ return X; }, false},
{{Instruction::SHR, {0, X}}, [=]{ return X; }, false},
{{Instruction::SHL, {X, 0}}, [=]{ return u256(0); }, true},
{{Instruction::SHR, {X, 0}}, [=]{ return u256(0); }, true},
{{Instruction::LT, {X, 0}}, [=]{ return u256(0); }, true},
{{Instruction::GT, {X, 0}}, [=]() -> Pattern { return {Instruction::ISZERO, {{Instruction::ISZERO, {X}}}}; }, false},
{{Instruction::GT, {X, ~u256(0)}}, [=]{ return u256(0); }, true},
{{Instruction::GT, {0, X}}, [=]{ return u256(0); }, true},
{{Instruction::AND, {{Instruction::BYTE, {X, Y}}, {u256(0xff)}}}, [=]() -> Pattern { return {Instruction::BYTE, {X, Y}}; }, false},
{{Instruction::BYTE, {X, 31}}, [=]() -> Pattern { return {Instruction::AND, {X, u256(0xff)}}; }, false}
};
}
@ -225,7 +237,9 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
Instruction::ADDRESS,
Instruction::CALLER,
Instruction::ORIGIN,
Instruction::COINBASE
Instruction::COINBASE,
Instruction::CREATE,
Instruction::CREATE2
})
{
u256 const mask = (u256(1) << 160) - 1;
@ -332,6 +346,20 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
}
}
rules.push_back({
// SHL(B, SHL(A, X)) -> SHL(min(A+B, 256), X)
{Instruction::SHL, {{B}, {Instruction::SHL, {{A}, {X}}}}},
[=]() -> Pattern { return {Instruction::SHL, {std::min(A.d() + B.d(), u256(256)), X}}; },
false
});
rules.push_back({
// SHR(B, SHR(A, X)) -> SHR(min(A+B, 256), X)
{Instruction::SHR, {{B}, {Instruction::SHR, {{A}, {X}}}}},
[=]() -> Pattern { return {Instruction::SHR, {std::min(A.d() + B.d(), u256(256)), X}}; },
false
});
return rules;
}

View File

@ -1,5 +1,6 @@
# Solidity Commons Library (Solidity related sharing bits between libsolidity and libyul)
set(sources
Common.h
CharStream.cpp
CharStream.h
ErrorReporter.cpp

View File

@ -1,48 +1,48 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
This file is derived from the file "scanner.cc", which was part of the
V8 project. The original copyright header follows:
Copyright 2006-2012, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This file is part of solidity.
*
* solidity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* solidity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with solidity. If not, see <http://www.gnu.org/licenses/>.
*
* This file is derived from the file "scanner.cc", which was part of the
* V8 project. The original copyright header follows:
*
* Copyright 2006-2012, the V8 project authors. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Christian <c@ethdev.com>
@ -85,8 +85,10 @@ string CharStream::lineAtPosition(int _position) const
lineStart = 0;
else
lineStart++;
return m_source.substr(lineStart, min(m_source.find('\n', lineStart),
m_source.size()) - lineStart);
return m_source.substr(
lineStart,
min(m_source.find('\n', lineStart), m_source.size()) - lineStart
);
}
tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const

View File

@ -1,48 +1,48 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
This file is derived from the file "scanner.h", which was part of the
V8 project. The original copyright header follows:
Copyright 2006-2012, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This file is part of solidity.
*
* solidity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* solidity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with solidity. If not, see <http://www.gnu.org/licenses/>.
*
* This file is derived from the file "scanner.h", which was part of the
* V8 project. The original copyright header follows:
*
* Copyright 2006-2012, the V8 project authors. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Christian <c@ethdev.com>

63
liblangutil/Common.h Normal file
View File

@ -0,0 +1,63 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace langutil
{
inline bool isDecimalDigit(char c)
{
return '0' <= c && c <= '9';
}
inline bool isHexDigit(char c)
{
return
isDecimalDigit(c) ||
('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F');
}
inline bool isLineTerminator(char c)
{
return c == '\n';
}
inline bool isWhiteSpace(char c)
{
return c == ' ' || c == '\n' || c == '\t' || c == '\r';
}
inline bool isIdentifierStart(char c)
{
return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
inline bool isIdentifierPart(char c)
{
return isIdentifierStart(c) || isDecimalDigit(c);
}
inline int hexValue(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else return -1;
}
}

View File

@ -25,14 +25,12 @@
#include <boost/optional.hpp>
#include <boost/operators.hpp>
namespace dev
{
namespace solidity
namespace langutil
{
/**
* A version specifier of the EVM we want to compile to.
* Defaults to the latest version.
* Defaults to the latest version deployed on Ethereum mainnet at the time of compiler release.
*/
class EVMVersion:
boost::less_than_comparable<EVMVersion>,
@ -46,10 +44,11 @@ public:
static EVMVersion spuriousDragon() { return {Version::SpuriousDragon}; }
static EVMVersion byzantium() { return {Version::Byzantium}; }
static EVMVersion constantinople() { return {Version::Constantinople}; }
static EVMVersion petersburg() { return {Version::Petersburg}; }
static boost::optional<EVMVersion> fromString(std::string const& _version)
{
for (auto const& v: {homestead(), tangerineWhistle(), spuriousDragon(), byzantium(), constantinople()})
for (auto const& v: {homestead(), tangerineWhistle(), spuriousDragon(), byzantium(), constantinople(), petersburg()})
if (_version == v.name())
return v;
return {};
@ -67,6 +66,7 @@ public:
case Version::SpuriousDragon: return "spuriousDragon";
case Version::Byzantium: return "byzantium";
case Version::Constantinople: return "constantinople";
case Version::Petersburg: return "petersburg";
}
return "INVALID";
}
@ -76,19 +76,19 @@ public:
bool hasStaticCall() const { return *this >= byzantium(); }
bool hasBitwiseShifting() const { return *this >= constantinople(); }
bool hasCreate2() const { return *this >= constantinople(); }
bool hasExtCodeHash() const { return *this >= constantinople(); }
/// Whether we have to retain the costs for the call opcode itself (false),
/// or whether we can just forward easily all remaining gas (true).
bool canOverchargeGasForCall() const { return *this >= tangerineWhistle(); }
private:
enum class Version { Homestead, TangerineWhistle, SpuriousDragon, Byzantium, Constantinople };
enum class Version { Homestead, TangerineWhistle, SpuriousDragon, Byzantium, Constantinople, Petersburg };
EVMVersion(Version _version): m_version(_version) {}
Version m_version = Version::Byzantium;
Version m_version = Version::Petersburg;
};
}
}

View File

@ -134,7 +134,7 @@ void ErrorReporter::clear()
m_errorList.clear();
}
void ErrorReporter::declarationError(SourceLocation const& _location, SecondarySourceLocation const&_secondaryLocation, string const& _description)
void ErrorReporter::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description)
{
error(
Error::Type::DeclarationError,

View File

@ -26,6 +26,9 @@
#include <liblangutil/Exceptions.h>
#include <liblangutil/SourceLocation.h>
#include <libdevcore/StringUtils.h>
#include <boost/range/adaptor/filtered.hpp>
namespace langutil
{
@ -87,6 +90,19 @@ public:
void typeError(SourceLocation const& _location, std::string const& _description);
template <typename... Strings>
void typeErrorConcatenateDescriptions(SourceLocation const& _location, Strings const&... _descriptions)
{
std::initializer_list<std::string> const descs = {_descriptions...};
solAssert(descs.size() > 0, "Need error descriptions!");
auto filterEmpty = boost::adaptors::filtered([](std::string const& _s) { return !_s.empty(); });
std::string errorStr = dev::joinHumanReadable(descs | filterEmpty);
error(Error::Type::TypeError, _location, errorStr);
}
void fatalTypeError(SourceLocation const& _location, std::string const& _description);
void docstringParsingError(std::string const& _description);
@ -119,8 +135,8 @@ private:
unsigned m_errorCount = 0;
unsigned m_warningCount = 0;
const unsigned c_maxWarningsAllowed = 256;
const unsigned c_maxErrorsAllowed = 256;
unsigned const c_maxWarningsAllowed = 256;
unsigned const c_maxErrorsAllowed = 256;
};
}

View File

@ -57,7 +57,7 @@ Error::Error(Type _type, SourceLocation const& _location, string const& _descrip
*this << errinfo_comment(_description);
}
Error::Error(Error::Type _type, const std::string& _description, const SourceLocation& _location):
Error::Error(Error::Type _type, std::string const& _description, SourceLocation const& _location):
Error(_type)
{
if (!_location.isEmpty())

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -42,13 +42,13 @@ struct UnimplementedFeatureError: virtual dev::Exception {};
/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
#define solAssert(CONDITION, DESCRIPTION) \
assertThrow(CONDITION, ::langutil::InternalCompilerError, DESCRIPTION)
assertThrow(CONDITION, ::langutil::InternalCompilerError, DESCRIPTION)
#define solUnimplementedAssert(CONDITION, DESCRIPTION) \
assertThrow(CONDITION, ::langutil::UnimplementedFeatureError, DESCRIPTION)
assertThrow(CONDITION, ::langutil::UnimplementedFeatureError, DESCRIPTION)
#define solUnimplemented(DESCRIPTION) \
solUnimplementedAssert(false, DESCRIPTION)
solUnimplementedAssert(false, DESCRIPTION)
class Error: virtual public dev::Exception
{

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,48 +1,48 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
This file is derived from the file "scanner.cc", which was part of the
V8 project. The original copyright header follows:
Copyright 2006-2012, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This file is part of solidity.
*
* solidity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* solidity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with solidity. If not, see <http://www.gnu.org/licenses/>.
*
* This file is derived from the file "scanner.cc", which was part of the
* V8 project. The original copyright header follows:
*
* Copyright 2006-2012, the V8 project authors. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Christian <c@ethdev.com>
@ -50,6 +50,7 @@
* Solidity scanner.
*/
#include <liblangutil/Common.h>
#include <liblangutil/Exceptions.h>
#include <liblangutil/Scanner.h>
#include <algorithm>
@ -61,46 +62,6 @@ using namespace std;
namespace langutil
{
namespace
{
bool isDecimalDigit(char c)
{
return '0' <= c && c <= '9';
}
bool isHexDigit(char c)
{
return isDecimalDigit(c)
|| ('a' <= c && c <= 'f')
|| ('A' <= c && c <= 'F');
}
bool isLineTerminator(char c)
{
return c == '\n';
}
bool isWhiteSpace(char c)
{
return c == ' ' || c == '\n' || c == '\t' || c == '\r';
}
bool isIdentifierStart(char c)
{
return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
bool isIdentifierPart(char c)
{
return isIdentifierStart(c) || isDecimalDigit(c);
}
int hexValue(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else return -1;
}
} // end anonymous namespace
std::string to_string(ScannerError _errorCode)
{
switch (_errorCode)
@ -595,7 +556,12 @@ void Scanner::scanToken()
token = Token::Period;
break;
case ':':
token = selectToken(Token::Colon);
// : :=
advance();
if (m_char == '=')
token = selectToken(Token::AssemblyAssign);
else
token = Token::Colon;
break;
case ';':
token = selectToken(Token::Semicolon);

View File

@ -1,48 +1,48 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
This file is derived from the file "scanner.h", which was part of the
V8 project. The original copyright header follows:
Copyright 2006-2012, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* This file is part of solidity.
*
* solidity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* solidity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with solidity. If not, see <http://www.gnu.org/licenses/>.
*
* This file is derived from the file "scanner.h", which was part of the
* V8 project. The original copyright header follows:
*
* Copyright 2006-2012, the V8 project authors. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Lefteris Karapetsas <lefteris@ethdev.com>

View File

@ -143,7 +143,7 @@ static Token keywordByName(string const& _name)
// and keywords to be put inside the keywords variable.
#define KEYWORD(name, string, precedence) {string, Token::name},
#define TOKEN(name, string, precedence)
static const map<string, Token> keywords({TOKEN_LIST(TOKEN, KEYWORD)});
static map<string, Token> const keywords({TOKEN_LIST(TOKEN, KEYWORD)});
#undef KEYWORD
#undef TOKEN
auto it = keywords.find(_name);

View File

@ -140,6 +140,8 @@ namespace langutil
T(Dec, "--", 0) \
K(Delete, "delete", 0) \
\
/* Inline Assembly Operators */ \
T(AssemblyAssign, ":=", 2) \
/* Keywords */ \
K(Anonymous, "anonymous", 0) \
K(As, "as", 0) \
@ -287,7 +289,7 @@ namespace TokenTraits
constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; }
constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; }
constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd ||
op == Token::Add || op == Token::Mul || op == Token::Equal || op == Token::NotEqual; }
op == Token::Add || op == Token::Mul || op == Token::Equal || op == Token::NotEqual; }
constexpr bool isArithmeticOp(Token op) { return Token::Add <= op && op <= Token::Exp; }
constexpr bool isCompareOp(Token op) { return Token::Equal <= op && op <= Token::GreaterThanOrEqual; }

View File

@ -649,22 +649,22 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
auto end = m_asm.newTag();
m_asm.append(Instruction::MSIZE); // Result will be original top of memory
m_asm.append(code[0].m_asm, 1); // The alloc argument N
m_asm.append(code[0].m_asm, 1); // The alloc argument N
m_asm.append(Instruction::DUP1);
m_asm.append(Instruction::ISZERO);// (alloc 0) does not change MSIZE
m_asm.appendJumpI(end);
m_asm.append(u256(1));
m_asm.append(Instruction::DUP2); // Copy N
m_asm.append(Instruction::SUB); // N-1
m_asm.append(Instruction::SUB); // N-1
m_asm.append(u256(0x1f)); // Bit mask
m_asm.append(Instruction::NOT); // Invert
m_asm.append(Instruction::AND); // Align N-1 on 32 byte boundary
m_asm.append(Instruction::NOT); // Invert
m_asm.append(Instruction::AND); // Align N-1 on 32 byte boundary
m_asm.append(Instruction::MSIZE); // MSIZE is cheap
m_asm.append(Instruction::ADD);
m_asm.append(Instruction::MLOAD); // Updates MSIZE
m_asm.append(Instruction::POP); // Discard the result of the MLOAD
m_asm.append(Instruction::POP); // Discard the result of the MLOAD
m_asm.append(end);
m_asm.append(Instruction::POP); // Discard duplicate N
m_asm.append(Instruction::POP); // Discard duplicate N
_s.usedAlloc = true;
}

View File

@ -65,7 +65,7 @@ private:
ReadCallback m_readFile;
};
static const CodeFragment NullCodeFragment;
static CodeFragment const NullCodeFragment;
}
}

View File

@ -28,7 +28,7 @@ using namespace std;
using namespace dev;
using namespace dev::lll;
bytes dev::lll::compileLLL(string const& _src, dev::solidity::EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile)
bytes dev::lll::compileLLL(string const& _src, langutil::EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile)
{
try
{
@ -36,7 +36,7 @@ bytes dev::lll::compileLLL(string const& _src, dev::solidity::EVMVersion _evmVer
cs.populateStandard();
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
if (_opt)
assembly = assembly.optimise(true, _evmVersion);
assembly = assembly.optimise(true, _evmVersion, true, 200);
bytes ret = assembly.assemble().bytecode;
for (auto i: cs.treesToKill)
killBigints(i);
@ -66,7 +66,7 @@ bytes dev::lll::compileLLL(string const& _src, dev::solidity::EVMVersion _evmVer
return bytes();
}
std::string dev::lll::compileLLLToAsm(std::string const& _src, EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile)
std::string dev::lll::compileLLLToAsm(std::string const& _src, langutil::EVMVersion _evmVersion, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile)
{
try
{
@ -74,7 +74,7 @@ std::string dev::lll::compileLLLToAsm(std::string const& _src, EVMVersion _evmVe
cs.populateStandard();
auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
if (_opt)
assembly = assembly.optimise(true, _evmVersion);
assembly = assembly.optimise(true, _evmVersion, true, 200);
string ret = assembly.assemblyString();
for (auto i: cs.treesToKill)
killBigints(i);

View File

@ -36,8 +36,8 @@ namespace lll
using ReadCallback = std::function<std::string(std::string const&)>;
std::string parseLLL(std::string const& _src);
std::string compileLLLToAsm(std::string const& _src, solidity::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
bytes compileLLL(std::string const& _src, solidity::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
std::string compileLLLToAsm(std::string const& _src, langutil::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
bytes compileLLL(std::string const& _src, langutil::EVMVersion _evmVersion, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
}
}

View File

@ -44,7 +44,7 @@ CodeFragment const& CompilerState::getDef(std::string const& _s) const
void CompilerState::populateStandard()
{
static const string s = "{"
static string const s = "{"
"(def 'panic () (asm INVALID))"
// Alternative macro version of alloc, which is currently implemented in the parser
// "(def 'alloc (n) (raw (msize) (when n (pop (mload (+ (msize) (& (- n 1) (~ 0x1f))))))))"

View File

@ -51,8 +51,6 @@ set(sources
codegen/ABIFunctions.h
codegen/ArrayUtils.cpp
codegen/ArrayUtils.h
codegen/AsmCodeGen.cpp
codegen/AsmCodeGen.h
codegen/Compiler.cpp
codegen/Compiler.h
codegen/CompilerContext.cpp
@ -82,14 +80,13 @@ set(sources
formal/VariableUsage.h
interface/ABI.cpp
interface/ABI.h
interface/AssemblyStack.cpp
interface/AssemblyStack.h
interface/CompilerStack.cpp
interface/CompilerStack.h
interface/GasEstimator.cpp
interface/GasEstimator.h
interface/Natspec.cpp
interface/Natspec.h
interface/OptimiserSettings.h
interface/ReadFile.h
interface/StandardCompiler.cpp
interface/StandardCompiler.h

View File

@ -120,7 +120,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
vector<VariableOccurrence const*> uninitializedAccessesOrdered(
exitInfo.uninitializedVariableAccesses.begin(),
exitInfo.uninitializedVariableAccesses.end()
);
);
boost::range::sort(
uninitializedAccessesOrdered,
[](VariableOccurrence const* lhs, VariableOccurrence const* rhs) -> bool

View File

@ -32,11 +32,12 @@ namespace dev
namespace solidity
{
/** Occurrence of a variable in a block of control flow.
* Stores the declaration of the referenced variable, the
* kind of the occurrence and possibly the node at which
* it occurred.
*/
/**
* Occurrence of a variable in a block of control flow.
* Stores the declaration of the referenced variable, the
* kind of the occurrence and possibly the node at which
* it occurred.
*/
class VariableOccurrence
{
public:
@ -85,11 +86,12 @@ private:
ASTNode const* m_occurrence = nullptr;
};
/** Node of the Control Flow Graph.
* The control flow is a directed graph connecting control flow blocks.
* An arc between two nodes indicates that the control flow can possibly
* move from its start node to its end node during execution.
*/
/**
* Node of the Control Flow Graph.
* The control flow is a directed graph connecting control flow blocks.
* An arc between two nodes indicates that the control flow can possibly
* move from its start node to its end node during execution.
*/
struct CFGNode
{
/// Entry nodes. All CFG nodes from which control flow may move into this node.

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -42,7 +42,7 @@ bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
bool DocStringAnalyser::visit(ContractDefinition const& _contract)
{
static const set<string> validTags = set<string>{"author", "title", "dev", "notice"};
static set<string> const validTags = set<string>{"author", "title", "dev", "notice"};
parseDocStrings(_contract, _contract.annotation(), validTags, "contracts");
return true;
@ -99,7 +99,7 @@ void DocStringAnalyser::handleConstructor(
DocumentedAnnotation& _annotation
)
{
static const set<string> validTags = set<string>{"author", "dev", "notice", "param"};
static set<string> const validTags = set<string>{"author", "dev", "notice", "param"};
parseDocStrings(_node, _annotation, validTags, "constructor");
checkParameters(_callable, _annotation);
}
@ -110,7 +110,7 @@ void DocStringAnalyser::handleCallable(
DocumentedAnnotation& _annotation
)
{
static const set<string> validTags = set<string>{"author", "dev", "notice", "return", "param"};
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param"};
parseDocStrings(_node, _annotation, validTags, "functions");
checkParameters(_callable, _annotation);
}

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -246,7 +246,7 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
fatalTypeError(_typeName.baseType().location(), "Illegal base type of storage size zero for array.");
if (Expression const* length = _typeName.length())
{
TypePointer lengthTypeGeneric = length->annotation().type;
TypePointer& lengthTypeGeneric = length->annotation().type;
if (!lengthTypeGeneric)
lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length);
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric.get());
@ -298,11 +298,13 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
}
declarations = m_resolver.nameFromCurrentScope(realName);
}
if (declarations.size() != 1)
if (declarations.size() > 1)
{
declarationError(_identifier.location, "Multiple matching identifiers. Resolving overloaded identifiers is not supported.");
return size_t(-1);
}
else if (declarations.size() == 0)
return size_t(-1);
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
if (var->isLocalVariable() && _crossesFunctionBoundary)
{
@ -322,9 +324,8 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
yul::AsmAnalyzer(
analysisInfo,
errorsIgnored,
EVMVersion(),
errorTypeForLoose,
yul::EVMDialect::looseAssemblyForEVM(),
yul::EVMDialect::looseAssemblyForEVM(EVMVersion{}),
resolver
).analyze(_inlineAssembly.operations());
return false;

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -139,14 +139,21 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
toString(arguments.size()) +
" were provided."
);
if (arguments.size() >= 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory()))
m_errorReporter.typeError(
arguments.front()->location(),
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
type(*arguments.front())->toString() +
" to bytes memory requested."
);
if (arguments.size() >= 1)
{
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory());
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
arguments.front()->location(),
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
type(*arguments.front())->toString() +
" to bytes memory requested.",
result.message()
);
}
if (arguments.size() < 2)
return {};
@ -262,16 +269,20 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
);
}
for (size_t i = 0; i < std::min(arguments->size(), parameterTypes.size()); ++i)
if (!type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
m_errorReporter.typeError(
{
BoolResult result = type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]);
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
(*arguments)[i]->location(),
"Invalid type for argument in constructor call. "
"Invalid implicit conversion from " +
type(*(*arguments)[i])->toString() +
" to " +
parameterTypes[i]->toString() +
" requested."
" requested.",
result.message()
);
}
}
}
@ -448,6 +459,9 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
)
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
if (_variable.typeName())
_variable.typeName()->accept(*this);
// type is filled either by ReferencesResolver directly from the type name or by
// TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
@ -511,14 +525,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
)
m_errorReporter.typeError(_variable.location(), "Array is too large to be encoded.");
break;
case Type::Category::Mapping:
if (auto mappingType = dynamic_cast<MappingType const*>(varType.get()))
if (
mappingType->keyType()->isDynamicallySized() &&
_variable.visibility() == Declaration::Visibility::Public
)
m_errorReporter.typeError(_variable.location(), "Dynamically-sized keys for public mappings are not supported.");
break;
default:
break;
}
@ -571,16 +577,20 @@ void TypeChecker::visitManually(
return;
}
for (size_t i = 0; i < arguments.size(); ++i)
if (!type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])))
m_errorReporter.typeError(
{
BoolResult result = type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i]));
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
arguments[i]->location(),
"Invalid type for argument in modifier invocation. "
"Invalid implicit conversion from " +
type(*arguments[i])->toString() +
" to " +
type(*(*parameters)[i])->toString() +
" requested."
" requested.",
result.message()
);
}
}
bool TypeChecker::visit(EventDefinition const& _eventDef)
@ -637,6 +647,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
{
solAssert(var->type(), "Expected variable type!");
if (var->isConstant())
{
m_errorReporter.typeError(_identifier.location, "Constant variables not supported by inline assembly.");
@ -713,9 +724,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
yul::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo,
m_errorReporter,
m_evmVersion,
Error::Type::SyntaxError,
yul::EVMDialect::looseAssemblyForEVM(),
yul::EVMDialect::looseAssemblyForEVM(m_evmVersion),
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
@ -772,29 +782,34 @@ void TypeChecker::endVisit(Return const& _return)
{
if (tupleType->components().size() != params->parameters().size())
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
else if (!tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes)))
m_errorReporter.typeError(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type " +
TupleType(returnTypes).toString(false) +
"."
);
else
{
BoolResult result = tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes));
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type " +
TupleType(returnTypes).toString(false) + ".",
result.message()
);
}
}
else if (params->parameters().size() != 1)
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
else
{
TypePointer const& expected = type(*params->parameters().front());
if (!type(*_return.expression())->isImplicitlyConvertibleTo(*expected))
m_errorReporter.typeError(
BoolResult result = type(*_return.expression())->isImplicitlyConvertibleTo(*expected);
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type (type of first return variable) " +
expected->toString() +
"."
expected->toString() + ".",
result.message()
);
}
}
@ -986,7 +1001,8 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
else
{
var.accept(*this);
if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type))
BoolResult result = valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type);
if (!result)
{
auto errorMsg = "Type " +
valueComponentType->toString() +
@ -1013,11 +1029,23 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
);
}
else
m_errorReporter.typeError(_statement.location(), errorMsg + ".");
m_errorReporter.typeErrorConcatenateDescriptions(
_statement.location(),
errorMsg + ".",
result.message()
);
}
}
}
if (valueTypes.size() != variables.size())
{
solAssert(m_errorReporter.hasErrors(), "Should have errors!");
for (auto const& var: variables)
if (var && !var->annotation().type)
BOOST_THROW_EXCEPTION(FatalError());
}
if (autoTypeDeductionNeeded)
{
if (!typeCanBeExpressed(variables))
@ -2046,25 +2074,27 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
}
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
"after argument-dependent lookup in " + exprType->toString() + ".";
if (memberName == "value")
if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
{
errorMsg.pop_back();
errorMsg += " - did you forget the \"payable\" modifier?";
}
else if (exprType->category() == Type::Category::Function)
{
if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
auto const& t = funType->returnParameterTypes();
if (memberName == "value")
{
auto const& t = funType->returnParameterTypes();
if (t.size() == 1)
if (
t.front()->category() == Type::Category::Contract ||
t.front()->category() == Type::Category::Struct
)
errorMsg += " Did you intend to call the function?";
if (funType->kind() == FunctionType::Kind::Creation)
errorMsg = "Constructor for " + t.front()->toString() + " must be payable for member \"value\" to be available.";
else
errorMsg = "Member \"value\" is only available for payable functions.";
}
else if (
t.size() == 1 &&
(t.front()->category() == Type::Category::Struct ||
t.front()->category() == Type::Category::Contract)
)
errorMsg += " Did you intend to call the function?";
}
if (exprType->category() == Type::Category::Contract)
else if (exprType->category() == Type::Category::Contract)
{
for (auto const& addressMember: AddressType::addressPayable().nativeMembers(nullptr))
if (addressMember.name == memberName)
{
@ -2073,6 +2103,21 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
break;
}
}
else if (auto addressType = dynamic_cast<AddressType const*>(exprType.get()))
{
// Trigger error when using send or transfer with a non-payable fallback function.
if (memberName == "send" || memberName == "transfer")
{
solAssert(
addressType->stateMutability() != StateMutability::Payable,
"Expected address not-payable as members were not found"
);
errorMsg = "\"send\" and \"transfer\" are only available for objects of type \"address payable\", not \"" + exprType->toString() + "\".";
}
}
m_errorReporter.fatalTypeError(
_memberAccess.location(),
errorMsg
@ -2090,12 +2135,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
annotation.type = possibleMembers.front().type;
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type.get()))
if (funType->bound() && !exprType->isImplicitlyConvertibleTo(*funType->selfType()))
m_errorReporter.typeError(
_memberAccess.location(),
"Function \"" + memberName + "\" cannot be called on an object of type " +
exprType->toString() + " (expected " + funType->selfType()->toString() + ")."
);
solAssert(
!funType->bound() || exprType->isImplicitlyConvertibleTo(*funType->selfType()),
"Function \"" + memberName + "\" cannot be called on an object of type " +
exprType->toString() + " (expected " + funType->selfType()->toString() + ")."
);
if (auto const* structType = dynamic_cast<StructType const*>(exprType.get()))
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
@ -2116,26 +2160,6 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
annotation.isLValue = annotation.referencedDeclaration->isLValue();
}
if (exprType->category() == Type::Category::Contract)
{
// Warn about using send or transfer with a non-payable fallback function.
if (auto callType = dynamic_cast<FunctionType const*>(type(_memberAccess).get()))
{
auto kind = callType->kind();
auto contractType = dynamic_cast<ContractType const*>(exprType.get());
solAssert(!!contractType, "Should be contract type.");
if (
(kind == FunctionType::Kind::Send || kind == FunctionType::Kind::Transfer) &&
!contractType->isPayable()
)
m_errorReporter.typeError(
_memberAccess.location(),
"Value transfer to a contract without a payable fallback function."
);
}
}
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
// although every subexpression is, so leaving this limited for now.
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))
@ -2159,6 +2183,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
"Circular reference for contract code access."
);
}
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "name")
annotation.isPure = true;
}
return false;
@ -2213,6 +2239,8 @@ bool TypeChecker::visit(IndexAccess const& _access)
case Type::Category::TypeType:
{
TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
if (dynamic_cast<ContractType const*>(typeType.actualType().get()))
m_errorReporter.typeError(_access.location(), "Index access for contracts or libraries is not possible.");
if (!index)
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
else
@ -2324,8 +2352,13 @@ bool TypeChecker::visit(Identifier const& _identifier)
if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration))
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
{
if (dynamic_cast<FunctionType const*>(annotation.type.get()))
annotation.isPure = true;
}
else if (dynamic_cast<TypeType const*>(annotation.type.get()))
annotation.isPure = true;
// Check for deprecated function names.
// The check is done here for the case without an actual function call.

View File

@ -48,7 +48,7 @@ class TypeChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
TypeChecker(EVMVersion _evmVersion, langutil::ErrorReporter& _errorReporter):
TypeChecker(langutil::EVMVersion _evmVersion, langutil::ErrorReporter& _errorReporter):
m_evmVersion(_evmVersion),
m_errorReporter(_errorReporter)
{}
@ -156,7 +156,7 @@ private:
ContractDefinition const* m_scope = nullptr;
EVMVersion m_evmVersion;
langutil::EVMVersion m_evmVersion;
/// Flag indicating whether we are currently inside an EmitStatement.
bool m_insideEmitStatement = false;

View File

@ -340,7 +340,8 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::Message, "data"},
{MagicType::Kind::Message, "sig"},
{MagicType::Kind::MetaType, "creationCode"},
{MagicType::Kind::MetaType, "runtimeCode"}
{MagicType::Kind::MetaType, "runtimeCode"},
{MagicType::Kind::MetaType, "name"},
};
set<MagicMember> static const payableMembers{
{MagicType::Kind::Message, "value"}

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -1209,7 +1209,7 @@ private:
class Continue: public Statement
{
public:
explicit Continue(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
explicit Continue(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
Statement(_location, _docString) {}
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
@ -1576,7 +1576,7 @@ private:
};
/**
* Index access to an array. Example: a[2]
* Index access to an array or mapping. Example: a[2]
*/
class IndexAccess: public Expression
{

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @date 2017

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @date 2017

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Lefteris <lefteris@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -113,9 +113,13 @@ bool ASTPrinter::visit(ParameterList const& _node)
bool ASTPrinter::visit(FunctionDefinition const& _node)
{
writeLine("FunctionDefinition \"" + _node.name() + "\"" +
(_node.isPublic() ? " - public" : "") +
(_node.stateMutability() == StateMutability::View ? " - const" : ""));
writeLine(
"FunctionDefinition \"" +
_node.name() +
"\"" +
(_node.isPublic() ? " - public" : "") +
(_node.stateMutability() == StateMutability::View ? " - const" : "")
);
printSourcePart(_node);
return goDeeper();
}
@ -305,8 +309,12 @@ bool ASTPrinter::visit(TupleExpression const& _node)
bool ASTPrinter::visit(UnaryOperation const& _node)
{
writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") +
") " + TokenTraits::toString(_node.getOperator()));
writeLine(
string("UnaryOperation (") +
(_node.isPrefixOperation() ? "prefix" : "postfix") +
") " +
TokenTraits::toString(_node.getOperator())
);
printType(_node);
printSourcePart(_node);
return goDeeper();

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>

View File

@ -35,13 +35,13 @@ enum class ExperimentalFeature
TestOnlyAnalysis
};
static const std::map<ExperimentalFeature, bool> ExperimentalFeatureOnlyAnalysis =
static std::map<ExperimentalFeature, bool> const ExperimentalFeatureOnlyAnalysis =
{
{ ExperimentalFeature::SMTChecker, true },
{ ExperimentalFeature::TestOnlyAnalysis, true },
};
static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames =
static std::map<std::string, ExperimentalFeature> const ExperimentalFeatureNames =
{
{ "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 },
{ "SMTChecker", ExperimentalFeature::SMTChecker },

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -496,8 +496,8 @@ BoolResult AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
return isImplicitlyConvertibleTo(_convertTo) ||
_convertTo.category() == Category::Integer ||
(_convertTo.category() == Category::FixedBytes && 160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8);
_convertTo.category() == Category::Integer ||
(_convertTo.category() == Category::FixedBytes && 160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8);
}
string AddressType::toString(bool) const
@ -1380,7 +1380,7 @@ string StringLiteralType::richIdentifier() const
return "t_stringliteral_" + toHex(keccak256(m_value).asBytes());
}
bool StringLiteralType::operator==(const Type& _other) const
bool StringLiteralType::operator==(Type const& _other) const
{
if (_other.category() != category())
return false;
@ -1463,7 +1463,7 @@ TypeResult FixedBytesType::binaryOperatorResult(Token _operator, TypePointer con
return TypePointer();
}
MemberList::MemberMap FixedBytesType::nativeMembers(const ContractDefinition*) const
MemberList::MemberMap FixedBytesType::nativeMembers(ContractDefinition const*) const
{
return MemberList::MemberMap{MemberList::Member{"length", make_shared<IntegerType>(8)}};
}
@ -1611,7 +1611,7 @@ string ReferenceType::identifierLocationSuffix() const
return id;
}
BoolResult ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
BoolResult ArrayType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.category() != category())
return false;
@ -1651,7 +1651,7 @@ BoolResult ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
}
}
BoolResult ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const
BoolResult ArrayType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (isImplicitlyConvertibleTo(_convertTo))
return true;
@ -1707,8 +1707,8 @@ bool ArrayType::operator==(Type const& _other) const
bool ArrayType::validForCalldata() const
{
if (auto arrayBaseType = dynamic_cast<ArrayType const*>(baseType().get()))
if (!arrayBaseType->validForCalldata())
return false;
if (!arrayBaseType->validForCalldata())
return false;
return unlimitedCalldataEncodedSize(true) <= numeric_limits<unsigned>::max();
}
@ -2010,7 +2010,7 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar
return variablesAndOffsets;
}
BoolResult StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
BoolResult StructType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.category() != category())
return false;
@ -3062,7 +3062,8 @@ string FunctionType::externalSignature() const
solAssert(false, "Invalid function type for requesting external signature.");
}
bool const inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
// "inLibrary" is only relevant if this is not an event.
bool const inLibrary = kind() != Kind::Event && dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
FunctionTypePointer external = interfaceFunctionType();
solAssert(!!external, "External function type requested.");
auto parameterTypes = external->parameterTypes();
@ -3298,7 +3299,7 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current
return members;
}
ModifierType::ModifierType(const ModifierDefinition& _modifier)
ModifierType::ModifierType(ModifierDefinition const& _modifier)
{
TypePointers params;
params.reserve(_modifier.parameters().size());
@ -3327,8 +3328,12 @@ bool ModifierType::operator==(Type const& _other) const
return false;
auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(),
other.m_parameterTypes.cbegin(), typeCompare))
if (!equal(
m_parameterTypes.cbegin(),
m_parameterTypes.cend(),
other.m_parameterTypes.cbegin(),
typeCompare
))
return false;
return true;
}
@ -3485,8 +3490,9 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_typeArgument).contractDefinition();
if (contract.canBeDeployed())
return MemberList::MemberMap({
{"creationCode", std::make_shared<ArrayType>(DataLocation::Memory)},
{"runtimeCode", std::make_shared<ArrayType>(DataLocation::Memory)}
{"creationCode", make_shared<ArrayType>(DataLocation::Memory)},
{"runtimeCode", make_shared<ArrayType>(DataLocation::Memory)},
{"name", make_shared<ArrayType>(DataLocation::Memory, true)},
});
else
return {};

View File

@ -1,18 +1,18 @@
/*
This file is part of solidity.
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
@ -216,7 +216,6 @@ public:
/// @returns number of bytes used by this type when encoded for CALL. If it is a dynamic type,
/// returns the size of the pointer (usually 32). Returns 0 if the type cannot be encoded
/// in calldata.
/// @note: This should actually not be called on types, where isDynamicallyEncoded returns true.
/// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
/// @returns the size of this data type in bytes when stored in memory. For memory-reference
@ -332,8 +331,8 @@ protected:
class AddressType: public Type
{
public:
static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
Category category() const override { return Category::Address; }
@ -707,7 +706,7 @@ public:
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(const Type& _other) const override;
bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override;
bool isDynamicallySized() const override { return m_hasDynamicLength; }
bool isDynamicallyEncoded() const override;
@ -736,6 +735,13 @@ public:
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
/// The offset to advance in calldata to move from one array element to the next.
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataEncodedSize(); }
/// The offset to advance in memory to move from one array element to the next.
unsigned memoryStride() const { return isByteArray() ? 1 : m_baseType->memoryHeadSize(); }
/// The offset to advance in storage to move from one array element to the next.
unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); }
private:
/// String is interpreted as a subtype of Bytes.
enum class ArrayKind { Ordinary, Bytes, String };
@ -823,7 +829,7 @@ public:
Category category() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
BoolResult isImplicitlyConvertibleTo(const Type& _convertTo) const override;
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override;

View File

@ -308,6 +308,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
break;
case Type::Category::Array:
case Type::Category::Struct:
case Type::Category::Mapping:
solAssert(_type.dataStoredIn(DataLocation::Storage), "Cleanup requested for non-storage reference type.");
templ("body", "cleaned := value");
break;
@ -1089,7 +1090,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
if (_options.dynamicInplace)
encode = Whiskers{"pos := <encode>(memberValue, pos)"}
("encode", abiEncodeAndReturnUpdatedPosFunction(*memberTypeFrom, *memberTypeTo, subOptions))
.render();
.render();
else
{
Whiskers encodeTempl(
@ -1262,7 +1263,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
return abiDecodingFunctionValueType(_type, _fromMemory);
}
string ABIFunctions::abiDecodingFunctionValueType(const Type& _type, bool _fromMemory)
string ABIFunctions::abiDecodingFunctionValueType(Type const& _type, bool _fromMemory)
{
TypePointer decodingType = _type.decodingType();
solAssert(decodingType, "");

View File

@ -50,7 +50,7 @@ using TypePointers = std::vector<TypePointer>;
class ABIFunctions
{
public:
explicit ABIFunctions(EVMVersion _evmVersion = EVMVersion{}) : m_evmVersion(_evmVersion) {}
explicit ABIFunctions(langutil::EVMVersion _evmVersion = langutil::EVMVersion{}) : m_evmVersion(_evmVersion) {}
/// @returns name of an assembly function to ABI-encode values of @a _givenTypes
/// into memory, converting the types to @a _targetTypes on the fly.
@ -286,7 +286,7 @@ private:
/// Map from function name to code for a multi-use function.
std::map<std::string, std::string> m_requestedFunctions;
std::set<std::string> m_externallyUsedFunctions;
EVMVersion m_evmVersion;
langutil::EVMVersion m_evmVersion;
};
}

View File

@ -623,7 +623,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD
<< Instruction::SWAP1;
// stack: data_pos_end data_pos
if (_type.isByteArray() || _type.baseType()->storageBytes() < 32)
if (_type.storageStride() < 32)
clearStorageLoop(make_shared<IntegerType>(256));
else
clearStorageLoop(_type.baseType());
@ -769,7 +769,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
// stack: ref new_length data_pos new_size delete_end
_context << Instruction::SWAP2 << Instruction::ADD;
// stack: ref new_length delete_end delete_start
if (_type.isByteArray() || _type.baseType()->storageBytes() < 32)
if (_type.storageStride() < 32)
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
else
ArrayUtils(_context).clearStorageLoop(_type.baseType());
@ -934,8 +934,11 @@ void ArrayUtils::clearStorageLoop(TypePointer const& _type) const
eth::AssemblyItem loopStart = _context.appendJumpToNew();
_context << loopStart;
// check for loop condition
_context << Instruction::DUP1 << Instruction::DUP3
<< Instruction::GT << Instruction::ISZERO;
_context <<
Instruction::DUP1 <<
Instruction::DUP3 <<
Instruction::GT <<
Instruction::ISZERO;
eth::AssemblyItem zeroLoopEnd = _context.newTag();
_context.appendConditionalJumpTo(zeroLoopEnd);
// delete

View File

@ -35,16 +35,20 @@ void Compiler::compileContract(
bytes const& _metadata
)
{
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize, m_optimizeRuns);
ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimiserSettings);
runtimeCompiler.compileContract(_contract, _otherCompilers);
m_runtimeContext.appendAuxiliaryData(_metadata);
// This might modify m_runtimeContext because it can access runtime functions at
// creation time.
ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize, 1);
OptimiserSettings creationSettings{m_optimiserSettings};
// The creation code will be executed at most once, so we modify the optimizer
// settings accordingly.
creationSettings.expectedExecutionsPerDeployment = 1;
ContractCompiler creationCompiler(&runtimeCompiler, m_context, creationSettings);
m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers);
m_context.optimise(m_optimize, m_optimizeRuns);
m_context.optimise(m_optimiserSettings);
}
std::shared_ptr<eth::Assembly> Compiler::runtimeAssemblyPtr() const

View File

@ -23,6 +23,7 @@
#pragma once
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/interface/OptimiserSettings.h>
#include <liblangutil/EVMVersion.h>
#include <libevmasm/Assembly.h>
#include <functional>
@ -34,9 +35,8 @@ namespace solidity {
class Compiler
{
public:
explicit Compiler(EVMVersion _evmVersion = EVMVersion{}, bool _optimize = false, unsigned _runs = 200):
m_optimize(_optimize),
m_optimizeRuns(_runs),
explicit Compiler(langutil::EVMVersion _evmVersion, OptimiserSettings _optimiserSettings):
m_optimiserSettings(std::move(_optimiserSettings)),
m_runtimeContext(_evmVersion),
m_context(_evmVersion, &m_runtimeContext)
{ }
@ -78,8 +78,7 @@ public:
eth::AssemblyItem functionEntryLabel(FunctionDefinition const& _function) const;
private:
bool const m_optimize;
unsigned const m_optimizeRuns;
OptimiserSettings const m_optimiserSettings;
CompilerContext m_runtimeContext;
size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present.
CompilerContext m_context;

View File

@ -23,7 +23,6 @@
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/AsmCodeGen.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/interface/Version.h>
@ -31,7 +30,9 @@
#include <libyul/AsmParser.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/backends/evm/AsmCodeGen.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/optimiser/Suite.h>
#include <libyul/YulString.h>
#include <liblangutil/ErrorReporter.h>
@ -129,8 +130,10 @@ void CompilerContext::appendMissingLowLevelFunctions()
}
}
void CompilerContext::addVariable(VariableDeclaration const& _declaration,
unsigned _offsetToCurrent)
void CompilerContext::addVariable(
VariableDeclaration const& _declaration,
unsigned _offsetToCurrent
)
{
solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, "");
unsigned sizeOnStack = _declaration.annotation().type->sizeOnStack();
@ -265,7 +268,7 @@ unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
return m_asm->deposit() - _offset - 1;
}
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(const Declaration& _declaration) const
pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
{
auto it = m_stateVariables.find(&_declaration);
solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
@ -326,12 +329,19 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
void CompilerContext::appendInlineAssembly(
string const& _assembly,
vector<string> const& _localVariables,
set<string> const&,
bool _system
set<string> const& _externallyUsedFunctions,
bool _system,
bool _optimise
)
{
int startStackHeight = stackHeight();
set<yul::YulString> externallyUsedIdentifiers;
for (auto const& fun: _externallyUsedFunctions)
externallyUsedIdentifiers.insert(yul::YulString(fun));
for (auto const& var: _localVariables)
externallyUsedIdentifiers.insert(yul::YulString(var));
yul::ExternalIdentifierAccess identifierAccess;
identifierAccess.resolve = [&](
yul::Identifier const& _identifier,
@ -374,25 +384,16 @@ void CompilerContext::appendInlineAssembly(
ErrorList errors;
ErrorReporter errorReporter(errors);
auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--"));
auto parserResult = yul::Parser(errorReporter, yul::EVMDialect::strictAssemblyForEVM()).parse(scanner, false);
auto parserResult = yul::Parser(errorReporter, yul::EVMDialect::strictAssemblyForEVM(m_evmVersion)).parse(scanner, false);
#ifdef SOL_OUTPUT_ASM
cout << yul::AsmPrinter()(*parserResult) << endl;
#endif
yul::AsmAnalysisInfo analysisInfo;
bool analyzerResult = false;
if (parserResult)
analyzerResult = yul::AsmAnalyzer(
analysisInfo,
errorReporter,
m_evmVersion,
boost::none,
yul::EVMDialect::strictAssemblyForEVM(),
identifierAccess.resolve
).analyze(*parserResult);
if (!parserResult || !errorReporter.errors().empty() || !analyzerResult)
auto reportError = [&](string const& _context)
{
string message =
"Error parsing/analyzing inline assembly block:\n"
"Error parsing/analyzing inline assembly block:\n" +
_context + "\n"
"------------------ Input: -----------------\n" +
_assembly + "\n"
"------------------ Errors: ----------------\n";
@ -404,10 +405,47 @@ void CompilerContext::appendInlineAssembly(
message += "-------------------------------------------\n";
solAssert(false, message);
};
yul::AsmAnalysisInfo analysisInfo;
bool analyzerResult = false;
if (parserResult)
analyzerResult = yul::AsmAnalyzer(
analysisInfo,
errorReporter,
boost::none,
yul::EVMDialect::strictAssemblyForEVM(m_evmVersion),
identifierAccess.resolve
).analyze(*parserResult);
if (!parserResult || !errorReporter.errors().empty() || !analyzerResult)
reportError("Invalid assembly generated by code generator.");
// Several optimizer steps cannot handle externally supplied stack variables,
// so we essentially only optimize the ABI functions.
if (_optimise && _localVariables.empty())
{
yul::OptimiserSuite::run(
yul::EVMDialect::strictAssemblyForEVM(m_evmVersion),
*parserResult,
analysisInfo,
externallyUsedIdentifiers
);
analysisInfo = yul::AsmAnalysisInfo{};
if (!yul::AsmAnalyzer(
analysisInfo,
errorReporter,
boost::none,
yul::EVMDialect::strictAssemblyForEVM(m_evmVersion),
identifierAccess.resolve
).analyze(*parserResult))
reportError("Optimizer introduced error into inline assembly.");
}
if (!errorReporter.errors().empty())
reportError("Failed to analyze inline assembly block.");
solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system);
yul::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, m_evmVersion, identifierAccess, _system, _optimise);
// Reset the source location to the one of the node (instead of the CODEGEN source location)
updateSourceLocation();
@ -446,6 +484,21 @@ void CompilerContext::updateSourceLocation()
m_asm->setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location());
}
eth::Assembly::OptimiserSettings CompilerContext::translateOptimiserSettings(OptimiserSettings const& _settings)
{
// Constructing it this way so that we notice changes in the fields.
eth::Assembly::OptimiserSettings asmSettings{false, false, false, false, false, false, m_evmVersion, 0};
asmSettings.isCreation = true;
asmSettings.runJumpdestRemover = _settings.runJumpdestRemover;
asmSettings.runPeephole = _settings.runPeephole;
asmSettings.runDeduplicate = _settings.runDeduplicate;
asmSettings.runCSE = _settings.runCSE;
asmSettings.runConstantOptimiser = _settings.runConstantOptimiser;
asmSettings.expectedExecutionsPerDeployment = _settings.expectedExecutionsPerDeployment;
asmSettings.evmVersion = m_evmVersion;
return asmSettings;
}
eth::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
Declaration const& _declaration,
CompilerContext& _context

View File

@ -27,6 +27,8 @@
#include <libsolidity/ast/Types.h>
#include <libsolidity/codegen/ABIFunctions.h>
#include <libsolidity/interface/OptimiserSettings.h>
#include <libevmasm/Assembly.h>
#include <libevmasm/Instruction.h>
#include <liblangutil/EVMVersion.h>
@ -50,7 +52,7 @@ class Compiler;
class CompilerContext
{
public:
explicit CompilerContext(EVMVersion _evmVersion = EVMVersion{}, CompilerContext* _runtimeContext = nullptr):
explicit CompilerContext(langutil::EVMVersion _evmVersion, CompilerContext* _runtimeContext = nullptr):
m_asm(std::make_shared<eth::Assembly>()),
m_evmVersion(_evmVersion),
m_runtimeContext(_runtimeContext),
@ -60,7 +62,7 @@ public:
m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data());
}
EVMVersion const& evmVersion() const { return m_evmVersion; }
langutil::EVMVersion const& evmVersion() const { return m_evmVersion; }
/// Update currently enabled set of experimental features.
void setExperimentalFeatures(std::set<ExperimentalFeature> const& _features) { m_experimentalFeatures = _features; }
@ -214,14 +216,15 @@ public:
std::string const& _assembly,
std::vector<std::string> const& _localVariables = std::vector<std::string>(),
std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>(),
bool _system = false
bool _system = false,
bool _optimise = false
);
/// Appends arbitrary data to the end of the bytecode.
void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); }
/// Run optimisation step.
void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, m_evmVersion, true, _runs); }
void optimise(OptimiserSettings const& _settings) { m_asm->optimise(translateOptimiserSettings(_settings)); }
/// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise.
CompilerContext* runtimeContext() const { return m_runtimeContext; }
@ -267,10 +270,12 @@ private:
std::vector<ContractDefinition const*>::const_iterator _searchStart
);
/// @returns an iterator to the contract directly above the given contract.
std::vector<ContractDefinition const*>::const_iterator superContract(const ContractDefinition &_contract) const;
std::vector<ContractDefinition const*>::const_iterator superContract(ContractDefinition const& _contract) const;
/// Updates source location set in the assembly.
void updateSourceLocation();
eth::Assembly::OptimiserSettings translateOptimiserSettings(OptimiserSettings const& _settings);
/**
* Helper class that manages function labels and ensures that referenced functions are
* compiled in a specific order.
@ -291,7 +296,7 @@ private:
Declaration const* nextFunctionToCompile() const;
/// Informs the queue that we are about to compile the given function, i.e. removes
/// the function from the queue of functions to compile.
void startFunction(const Declaration &_function);
void startFunction(Declaration const& _function);
/// Labels pointing to the entry points of functions.
std::map<Declaration const*, eth::AssemblyItem> m_entryLabels;
@ -305,7 +310,7 @@ private:
eth::AssemblyPointer m_asm;
/// Version of the EVM to compile against.
EVMVersion m_evmVersion;
langutil::EVMVersion m_evmVersion;
/// Activated experimental features.
std::set<ExperimentalFeature> m_experimentalFeatures;
/// Other already compiled contracts to be used in contract creation calls.

View File

@ -37,11 +37,11 @@ namespace dev
namespace solidity
{
const unsigned CompilerUtils::dataStartOffset = 4;
const size_t CompilerUtils::freeMemoryPointer = 64;
const size_t CompilerUtils::zeroPointer = CompilerUtils::freeMemoryPointer + 32;
const size_t CompilerUtils::generalPurposeMemoryStart = CompilerUtils::zeroPointer + 32;
const unsigned CompilerUtils::identityContractAddress = 4;
unsigned const CompilerUtils::dataStartOffset = 4;
size_t const CompilerUtils::freeMemoryPointer = 64;
size_t const CompilerUtils::zeroPointer = CompilerUtils::freeMemoryPointer + 32;
size_t const CompilerUtils::generalPurposeMemoryStart = CompilerUtils::zeroPointer + 32;
unsigned const CompilerUtils::identityContractAddress = 4;
static_assert(CompilerUtils::freeMemoryPointer >= 64, "Free memory pointer must not overlap with scratch area.");
static_assert(CompilerUtils::zeroPointer >= CompilerUtils::freeMemoryPointer + 32, "Zero pointer must not overlap with free memory pointer.");
@ -70,6 +70,13 @@ void CompilerUtils::allocateMemory()
storeFreeMemoryPointer();
}
void CompilerUtils::allocateMemory(u256 const& size)
{
fetchFreeMemoryPointer();
m_context << Instruction::DUP1 << size << Instruction::ADD;
storeFreeMemoryPointer();
}
void CompilerUtils::toSizeAfterFreeMemoryPointer()
{
fetchFreeMemoryPointer();
@ -243,7 +250,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
gt(add(array_data_start, mul(array_length, <item_size>)), input_end)
) { revert(0, 0) }
})");
templ("item_size", to_string(arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true)));
templ("item_size", to_string(arrayType.calldataStride()));
m_context.appendInlineAssembly(templ.render(), {"input_end", "base_offset", "offset", "ptr"});
// stack: v1 v2 ... v(k-1) input_end base_offset current_offset v(k)
moveIntoStack(3);
@ -279,11 +286,10 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
// stack: input_end base_offset next_pointer array_length data_pointer
m_context << Instruction::SWAP2;
// stack: input_end base_offset data_pointer array_length next_pointer
unsigned itemSize = arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true);
m_context.appendInlineAssembly(R"({
if or(
gt(array_length, 0x100000000),
gt(add(data_ptr, mul(array_length, )" + to_string(itemSize) + R"()), input_end)
gt(add(data_ptr, mul(array_length, )" + to_string(arrayType.calldataStride()) + R"()), input_end)
) { revert(0, 0) }
})", {"input_end", "base_offset", "data_ptr", "array_length", "next_ptr"});
}
@ -517,7 +523,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
codecopy(memptr, codesize(), size)
memptr := add(memptr, size)
})");
templ("element_size", to_string(_type.isByteArray() ? 1 : _type.baseType()->memoryHeadSize()));
templ("element_size", to_string(_type.memoryStride()));
m_context.appendInlineAssembly(templ.render(), {"length", "memptr"});
}
else
@ -653,10 +659,13 @@ void CompilerUtils::convertType(
bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer;
if (chopSignBitsPending)
{
const IntegerType& targetIntegerType = dynamic_cast<const IntegerType &>(_targetType);
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
chopSignBitsPending = targetIntegerType.isSigned();
}
if (targetTypeCategory == Type::Category::FixedPoint)
solUnimplemented("Not yet implemented - FixedPointType.");
switch (stackTypeCategory)
{
case Type::Category::FixedBytes:
@ -811,9 +820,8 @@ void CompilerUtils::convertType(
{
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
solAssert(arrayType.isByteArray(), "");
u256 storageSize(32 + ((data.size() + 31) / 32) * 32);
m_context << storageSize;
allocateMemory();
unsigned storageSize = 32 + ((data.size() + 31) / 32) * 32;
allocateMemory(storageSize);
// stack: mempos
m_context << Instruction::DUP1 << u256(data.size());
storeInMemoryDynamic(IntegerType::uint256());
@ -936,8 +944,7 @@ void CompilerUtils::convertType(
{
case DataLocation::Storage:
// stack: <source ref>
m_context << typeOnStack.memorySize();
allocateMemory();
allocateMemory(typeOnStack.memorySize());
m_context << Instruction::SWAP1 << Instruction::DUP2;
// stack: <memory ptr> <source ref> <memory ptr>
for (auto const& member: typeOnStack.members(nullptr))
@ -1101,8 +1108,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
1,
[type](CompilerContext& _context) {
CompilerUtils utils(_context);
_context << u256(max(32u, type->calldataEncodedSize()));
utils.allocateMemory();
utils.allocateMemory(max(32u, type->calldataEncodedSize()));
_context << Instruction::DUP1;
if (auto structType = dynamic_cast<StructType const*>(type.get()))

View File

@ -49,6 +49,10 @@ public:
/// Stack pre: <size>
/// Stack post: <mem_start>
void allocateMemory();
/// Allocates a number of bytes in memory as given on the stack.
/// Stack pre:
/// Stack post: <mem_start>
void allocateMemory(u256 const& size);
/// Appends code that transforms memptr to (memptr - free_memptr) memptr
/// Stack pre: <mem_end>
/// Stack post: <size> <mem_start>
@ -84,7 +88,6 @@ public:
);
/// Stores a 256 bit integer from stack in memory.
/// @param _offset offset in memory
/// @param _type type of the data on the stack
void storeInMemory(unsigned _offset);
/// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack
/// and also updates that. For reference types, only copies the data pointer. Fails for
@ -187,6 +190,11 @@ public:
/// Stack post:
void memoryCopy();
/// Stores the given string in memory.
/// Stack pre: mempos
/// Stack post:
void storeStringData(bytesConstRef _data);
/// Converts the combined and left-aligned (right-aligned if @a _rightAligned is true)
/// external function type <address><function identifier> into two stack slots:
/// address (right aligned), function identifier (right aligned)
@ -273,23 +281,18 @@ public:
/// Bytes we need to the start of call data.
/// - The size in bytes of the function (hash) identifier.
static const unsigned dataStartOffset;
static unsigned const dataStartOffset;
/// Position of the free-memory-pointer in memory;
static const size_t freeMemoryPointer;
static size_t const freeMemoryPointer;
/// Position of the memory slot that is always zero.
static const size_t zeroPointer;
static size_t const zeroPointer;
/// Starting offset for memory available to the user (aka the contract).
static const size_t generalPurposeMemoryStart;
static size_t const generalPurposeMemoryStart;
private:
/// Address of the precompiled identity contract.
static const unsigned identityContractAddress;
/// Stores the given string in memory.
/// Stack pre: mempos
/// Stack post:
void storeStringData(bytesConstRef _data);
static unsigned const identityContractAddress;
/// Appends code that cleans higher-order bits for integer types.
void cleanHigherOrderBits(IntegerType const& _typeOnStack);

View File

@ -21,14 +21,16 @@
*/
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/AsmCodeGen.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/codegen/ContractCompiler.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libyul/backends/evm/AsmCodeGen.h>
#include <libevmasm/Instruction.h>
#include <libevmasm/Assembly.h>
#include <libevmasm/GasMeter.h>
#include <liblangutil/ErrorReporter.h>
#include <boost/range/adaptor/reversed.hpp>
@ -175,6 +177,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered");
m_context.pushSubroutineSize(m_context.runtimeSub());
m_context.pushSubroutineOffset(m_context.runtimeSub());
// This code replaces the address added by appendDeployTimeAddress().
m_context.appendInlineAssembly(R"(
{
// If code starts at 11, an mstore(0) writes to the full PUSH20 plus data
@ -182,8 +185,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
let codepos := 11
codecopy(codepos, subOffset, subSize)
// Check that the first opcode is a PUSH20
switch eq(0x73, byte(0, mload(codepos)))
case 0 { invalid() }
if iszero(eq(0x73, byte(0, mload(codepos)))) { invalid() }
mstore(0, address())
mstore8(codepos, 0x73)
return(codepos, subSize)
@ -353,7 +355,7 @@ bool hasPayableFunctions(ContractDefinition const& _contract)
void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contract)
{
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.interfaceFunctions();
map<FixedHash<4>, const eth::AssemblyItem> callDataUnpackerEntryPoints;
map<FixedHash<4>, eth::AssemblyItem const> callDataUnpackerEntryPoints;
if (_contract.isLibrary())
{
@ -389,7 +391,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
sortedIDs.emplace_back(it.first);
}
std::sort(sortedIDs.begin(), sortedIDs.end());
appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs);
appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimiserSettings.expectedExecutionsPerDeployment);
}
m_context << notFound;
@ -482,7 +484,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr
solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library.");
for (VariableDeclaration const* variable: _contract.stateVariables())
if (variable->value() && !variable->isConstant())
ExpressionCompiler(m_context, m_optimise).appendStateVariableInitialization(*variable);
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable);
}
bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
@ -495,9 +497,9 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration)
m_continueTags.clear();
if (_variableDeclaration.isConstant())
ExpressionCompiler(m_context, m_optimise).appendConstStateVariableAccessor(_variableDeclaration);
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendConstStateVariableAccessor(_variableDeclaration);
else
ExpressionCompiler(m_context, m_optimise).appendStateVariableAccessor(_variableDeclaration);
ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableAccessor(_variableDeclaration);
return false;
}
@ -713,10 +715,11 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
}
};
solAssert(_inlineAssembly.annotation().analysisInfo, "");
CodeGenerator::assemble(
yul::CodeGenerator::assemble(
_inlineAssembly.operations(),
*_inlineAssembly.annotation().analysisInfo,
*m_context.assemblyPtr(),
m_context.evmVersion(),
identifierAccess
);
m_context.setStackOffset(startStackHeight);
@ -975,7 +978,13 @@ void ContractCompiler::appendMissingFunctions()
m_context.appendMissingLowLevelFunctions();
auto abiFunctions = m_context.abiFunctions().requestedFunctions();
if (!abiFunctions.first.empty())
m_context.appendInlineAssembly("{" + move(abiFunctions.first) + "}", {}, abiFunctions.second, true);
m_context.appendInlineAssembly(
"{" + move(abiFunctions.first) + "}",
{},
abiFunctions.second,
true,
m_optimiserSettings.runYulOptimiser
);
}
void ContractCompiler::appendModifierOrFunctionCode()
@ -1050,7 +1059,7 @@ void ContractCompiler::appendStackVariableInitialisation(VariableDeclaration con
void ContractCompiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
{
ExpressionCompiler expressionCompiler(m_context, m_optimise);
ExpressionCompiler expressionCompiler(m_context, m_optimiserSettings.runOrderLiterals);
expressionCompiler.compile(_expression);
if (_targetType)
CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);

View File

@ -28,8 +28,10 @@
#include <functional>
#include <ostream>
namespace dev {
namespace solidity {
namespace dev
{
namespace solidity
{
/**
* Code generator at the contract level. Can be used to generate code for exactly one contract
@ -38,13 +40,15 @@ namespace solidity {
class ContractCompiler: private ASTConstVisitor
{
public:
explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimise, size_t _optimise_runs = 200):
m_optimise(_optimise),
m_optimise_runs(_optimise_runs),
explicit ContractCompiler(
ContractCompiler* _runtimeCompiler,
CompilerContext& _context,
OptimiserSettings _optimiserSettings
):
m_optimiserSettings(std::move(_optimiserSettings)),
m_runtimeCompiler(_runtimeCompiler),
m_context(_context)
{
m_context = CompilerContext(_context.evmVersion(), _runtimeCompiler ? &_runtimeCompiler->m_context : nullptr);
}
void compileContract(
@ -130,8 +134,7 @@ private:
/// Sets the stack height for the visited loop.
void storeStackHeight(ASTNode const* _node);
bool const m_optimise;
size_t const m_optimise_runs = 200;
OptimiserSettings const m_optimiserSettings;
/// Pointer to the runtime compiler in case this is a creation compiler.
ContractCompiler* m_runtimeCompiler = nullptr;
CompilerContext& m_context;

View File

@ -106,18 +106,49 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
solUnimplementedAssert(
!paramTypes[i]->isDynamicallySized(),
"Accessors for mapping with dynamically-sized keys not yet implemented."
);
// pop offset
m_context << Instruction::POP;
// move storage offset to memory.
utils().storeInMemory(32);
// move key to memory.
utils().copyToStackTop(paramTypes.size() - i, 1);
utils().storeInMemory(0);
m_context << u256(64) << u256(0) << Instruction::KECCAK256;
if (paramTypes[i]->isDynamicallySized())
{
solAssert(
dynamic_cast<ArrayType const&>(*paramTypes[i]).isByteArray(),
"Expected string or byte array for mapping key type"
);
// stack: <keys..> <slot position>
// copy key[i] to top.
utils().copyToStackTop(paramTypes.size() - i + 1, 1);
m_context.appendInlineAssembly(R"({
let key_len := mload(key_ptr)
// Temp. use the memory after the array data for the slot
// position
let post_data_ptr := add(key_ptr, add(key_len, 0x20))
let orig_data := mload(post_data_ptr)
mstore(post_data_ptr, slot_pos)
let hash := keccak256(add(key_ptr, 0x20), add(key_len, 0x20))
mstore(post_data_ptr, orig_data)
slot_pos := hash
})", {"slot_pos", "key_ptr"});
m_context << Instruction::POP;
}
else
{
solAssert(paramTypes[i]->isValueType(), "Expected value type for mapping key");
// move storage offset to memory.
utils().storeInMemory(32);
// move key to memory.
utils().copyToStackTop(paramTypes.size() - i, 1);
utils().storeInMemory(0);
m_context << u256(64) << u256(0);
m_context << Instruction::KECCAK256;
}
// push offset
m_context << u256(0);
returnType = mappingType->valueType();
@ -286,8 +317,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
m_context << max(u256(32u), arrayType.memorySize());
utils().allocateMemory();
utils().allocateMemory(max(u256(32u), arrayType.memorySize()));
m_context << Instruction::DUP1;
for (auto const& component: _tuple.components())
@ -418,7 +448,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
{
return dynamic_cast<Literal const*>(&_e) || _e.annotation().type->category() == Type::Category::RationalNumber;
};
bool swap = m_optimize && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
bool swap = m_optimiseOrderLiterals && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
if (swap)
{
leftExpression.accept(*this);
@ -496,8 +526,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type);
auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
m_context << max(u256(32u), structType.memorySize());
utils().allocateMemory();
utils().allocateMemory(max(u256(32u), structType.memorySize()));
m_context << Instruction::DUP1;
for (unsigned i = 0; i < arguments.size(); ++i)
@ -1310,8 +1339,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
utils().leftShiftNumberOnStack(224);
}
else
solAssert(!!_memberAccess.expression().annotation().type->memberType(member),
"Invalid member access to function.");
solAssert(
!!_memberAccess.expression().annotation().type->memberType(member),
"Invalid member access to function."
);
break;
case Type::Category::Magic:
// we can ignore the kind of magic and only look at the name of the member
@ -1359,6 +1390,17 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
);
m_context << Instruction::POP;
}
else if (member == "name")
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
utils().allocateMemory(contract.name().length() + 32);
// store string length
m_context << u256(contract.name().length()) << Instruction::DUP2 << Instruction::MSTORE;
// adjust pointer
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
utils().storeStringData(contract.name());
}
else
solAssert(false, "Unknown magic member.");
break;
@ -1965,12 +2007,18 @@ void ExpressionCompiler::appendExternalFunctionCall(
// If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place.
// Move arguments to memory, will not update the free memory pointer (but will update the memory
// pointer on the stack).
bool encodeInPlace = _functionType.takesArbitraryParameters() || _functionType.isBareCall();
if (_functionType.kind() == FunctionType::Kind::ECRecover)
// This would be the only combination of padding and in-place encoding,
// but all parameters of ecrecover are value types anyway.
encodeInPlace = false;
bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall;
utils().encodeToMemory(
argumentTypes,
parameterTypes,
_functionType.padArguments(),
_functionType.takesArbitraryParameters() || _functionType.isBareCall(),
isDelegateCall
encodeInPlace,
encodeForLibraryCall
);
// Stack now:
@ -2083,7 +2131,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
mstore(v, returndatasize())
returndatacopy(add(v, 0x20), 0, returndatasize())
}
})", {"v"});
})", {"v"});
}
else
utils().pushZeroPointer();

View File

@ -55,11 +55,8 @@ class ArrayType;
class ExpressionCompiler: private ASTConstVisitor
{
public:
/// Appends code for a State Variable accessor function
static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false);
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false):
m_optimize(_optimize), m_context(_compilerContext) {}
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimiseOrderLiterals):
m_optimiseOrderLiterals(_optimiseOrderLiterals), m_context(_compilerContext) {}
/// Compile the given @a _expression and leave its value on the stack.
void compile(Expression const& _expression);
@ -71,7 +68,7 @@ public:
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
/// Appends code for a Constant State Variable accessor function
void appendConstStateVariableAccessor(const VariableDeclaration& _varDecl);
void appendConstStateVariableAccessor(VariableDeclaration const& _varDecl);
private:
bool visit(Conditional const& _condition) override;
@ -127,7 +124,7 @@ private:
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();
bool m_optimize;
bool m_optimiseOrderLiterals;
CompilerContext& m_context;
std::unique_ptr<LValue> m_currentLValue;

View File

@ -473,7 +473,7 @@ void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeRefer
m_context << Instruction::SWAP1 << Instruction::SSTORE;
}
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const ArrayType& _arrayType):
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType):
LValue(_compilerContext, _arrayType.memberType("length").get()),
m_arrayType(_arrayType)
{

View File

@ -21,7 +21,6 @@
#include <libsolidity/formal/VariableUsage.h>
#include <libsolidity/formal/SymbolicTypes.h>
#include <liblangutil/ErrorReporter.h>
#include <libdevcore/StringUtils.h>
#include <boost/range/adaptor/map.hpp>
@ -109,6 +108,7 @@ bool SMTChecker::visit(FunctionDefinition const& _function)
m_expressions.clear();
m_globalContext.clear();
m_uninterpretedTerms.clear();
m_overflowTargets.clear();
resetStateVariables();
initializeLocalVariables(_function);
m_loopExecutionHappened = false;
@ -126,7 +126,10 @@ void SMTChecker::endVisit(FunctionDefinition const&)
// Otherwise we remove any local variables from the context and
// keep the state variables.
if (isRootFunction())
{
checkUnderOverflow();
removeLocalVariables();
}
m_functionPath.pop_back();
}
@ -316,21 +319,56 @@ void SMTChecker::endVisit(TupleExpression const& _tuple)
defineExpr(_tuple, expr(*_tuple.components()[0]));
}
void SMTChecker::checkUnderOverflow(smt::Expression _value, IntegerType const& _type, SourceLocation const& _location)
void SMTChecker::addOverflowTarget(
OverflowTarget::Type _type,
TypePointer _intType,
smt::Expression _value,
SourceLocation const& _location
)
{
checkCondition(
_value < minValue(_type),
_location,
"Underflow (resulting value less than " + formatNumberReadable(_type.minValue()) + ")",
"<result>",
&_value
m_overflowTargets.emplace_back(
_type,
std::move(_intType),
std::move(_value),
currentPathConditions(),
_location
);
}
void SMTChecker::checkUnderOverflow()
{
for (auto& target: m_overflowTargets)
{
if (target.type != OverflowTarget::Type::Overflow)
checkUnderflow(target);
if (target.type != OverflowTarget::Type::Underflow)
checkOverflow(target);
}
}
void SMTChecker::checkUnderflow(OverflowTarget& _target)
{
solAssert(_target.type != OverflowTarget::Type::Overflow, "");
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
checkCondition(
_value > maxValue(_type),
_location,
"Overflow (resulting value larger than " + formatNumberReadable(_type.maxValue()) + ")",
_target.path && _target.value < minValue(*intType),
_target.location,
"Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ")",
"<result>",
&_value
&_target.value
);
}
void SMTChecker::checkOverflow(OverflowTarget& _target)
{
solAssert(_target.type != OverflowTarget::Type::Underflow, "");
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
checkCondition(
_target.path && _target.value > maxValue(*intType),
_target.location,
"Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ")",
"<result>",
&_target.value
);
}
@ -376,8 +414,13 @@ void SMTChecker::endVisit(UnaryOperation const& _op)
case Token::Sub: // -
{
defineExpr(_op, 0 - expr(_op.subExpression()));
if (auto intType = dynamic_cast<IntegerType const*>(_op.annotation().type.get()))
checkUnderOverflow(expr(_op), *intType, _op.location());
if (_op.annotation().type->category() == Type::Category::Integer)
addOverflowTarget(
OverflowTarget::Type::All,
_op.annotation().type,
expr(_op),
_op.location()
);
break;
}
default:
@ -582,10 +625,8 @@ void SMTChecker::endVisit(Identifier const& _identifier)
{
// Will be translated as part of the node that requested the lvalue.
}
else if (dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
{
else if (_identifier.annotation().type->category() == Type::Category::Function)
visitFunctionIdentifier(_identifier);
}
else if (isSupportedType(_identifier.annotation().type->category()))
{
if (VariableDeclaration const* decl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
@ -654,6 +695,7 @@ void SMTChecker::visitFunctionIdentifier(Identifier const& _identifier)
void SMTChecker::endVisit(Literal const& _literal)
{
solAssert(_literal.annotation().type, "Expected type for AST node");
Type const& type = *_literal.annotation().type;
if (isNumber(type.category()))
@ -853,9 +895,28 @@ void SMTChecker::arithmeticOperation(BinaryOperation const& _op)
m_interface->addAssertion(right != 0);
}
checkUnderOverflow(value, intType, _op.location());
addOverflowTarget(
OverflowTarget::Type::All,
_op.annotation().commonType,
value,
_op.location()
);
smt::Expression intValueRange = (0 - minValue(intType)) + maxValue(intType) + 1;
defineExpr(_op, smt::Expression::ite(
value > maxValue(intType) || value < minValue(intType),
value % intValueRange,
value
));
if (intType.isSigned())
{
defineExpr(_op, smt::Expression::ite(
expr(_op) > maxValue(intType),
expr(_op) - intValueRange,
expr(_op)
));
}
defineExpr(_op, value);
break;
}
default:
@ -944,11 +1005,11 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, Expression con
void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expression const& _value, SourceLocation const& _location)
{
TypePointer type = _variable.type();
if (auto const* intType = dynamic_cast<IntegerType const*>(type.get()))
checkUnderOverflow(_value, *intType, _location);
else if (dynamic_cast<AddressType const*>(type.get()))
checkUnderOverflow(_value, IntegerType(160), _location);
else if (dynamic_cast<MappingType const*>(type.get()))
if (type->category() == Type::Category::Integer)
addOverflowTarget(OverflowTarget::Type::All, type, _value, _location);
else if (type->category() == Type::Category::Address)
addOverflowTarget(OverflowTarget::Type::All, make_shared<IntegerType>(160), _value, _location);
else if (type->category() == Type::Category::Mapping)
arrayAssignment();
m_interface->addAssertion(newValue(_variable) == _value);
}
@ -1371,7 +1432,7 @@ void SMTChecker::createExpr(Expression const& _e)
void SMTChecker::defineExpr(Expression const& _e, smt::Expression _value)
{
createExpr(_e);
solAssert(isSupportedType(*_e.annotation().type), "Equality operator applied to type that is not fully supported");
solAssert(smtKind(_e.annotation().type->category()) != smt::Kind::Function, "Equality operator applied to type that is not fully supported");
m_interface->addAssertion(expr(_e) == _value);
}

View File

@ -137,9 +137,33 @@ private:
Expression const& _condition,
std::string const& _description
);
/// Checks that the value is in the range given by the type.
void checkUnderOverflow(smt::Expression _value, IntegerType const& _Type, langutil::SourceLocation const& _location);
struct OverflowTarget
{
enum class Type { Underflow, Overflow, All } type;
TypePointer intType;
smt::Expression value;
smt::Expression path;
langutil::SourceLocation const& location;
OverflowTarget(Type _type, TypePointer _intType, smt::Expression _value, smt::Expression _path, langutil::SourceLocation const& _location):
type(_type),
intType(_intType),
value(_value),
path(_path),
location(_location)
{
solAssert(dynamic_cast<IntegerType const*>(intType.get()), "");
}
};
/// Checks that the value is in the range given by the type.
void checkUnderflow(OverflowTarget& _target);
void checkOverflow(OverflowTarget& _target);
/// Calls the functions above for all elements in m_overflowTargets accordingly.
void checkUnderOverflow();
/// Adds an overflow target for lazy check at the end of the function.
void addOverflowTarget(OverflowTarget::Type _type, TypePointer _intType, smt::Expression _value, langutil::SourceLocation const& _location);
std::pair<smt::CheckResult, std::vector<std::string>>
checkSatisfiableAndGenerateModel(std::vector<smt::Expression> const& _expressionsToEvaluate);
@ -244,6 +268,8 @@ private:
bool isRootFunction();
/// Returns true if _funDef was already visited.
bool visitedFunction(FunctionDefinition const* _funDef);
std::vector<OverflowTarget> m_overflowTargets;
};
}

Some files were not shown because too many files have changed in this diff Show More