diff --git a/.circleci/config.yml b/.circleci/config.yml index 4706fe6c0..a859b8464 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -627,14 +627,14 @@ jobs: - checkout - restore_cache: keys: - - dependencies-osx-{{ checksum ".circleci/osx_install_dependencies.sh" }} + - dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }} # DO NOT EDIT between here and save_cache, but rather edit ./circleci/osx_install_dependencies.sh # WARNING! If you do edit anything here instead, remember to invalidate the cache manually. - run: name: Install build dependencies command: ./.circleci/osx_install_dependencies.sh - save_cache: - key: dependencies-osx-{{ checksum ".circleci/osx_install_dependencies.sh" }} + key: dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }} paths: - /usr/local/bin - /usr/local/sbin @@ -663,7 +663,7 @@ jobs: - checkout - restore_cache: keys: - - dependencies-osx-{{ checksum ".circleci/osx_install_dependencies.sh" }} + - dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }} - attach_workspace: at: . - run: *run_soltest @@ -679,7 +679,7 @@ jobs: - checkout - restore_cache: keys: - - dependencies-osx-{{ checksum ".circleci/osx_install_dependencies.sh" }} + - dependencies-osx-{{ arch }}-{{ checksum ".circleci/osx_install_dependencies.sh" }} - attach_workspace: at: . - run: *run_cmdline_tests @@ -886,14 +886,14 @@ jobs: - checkout - restore_cache: keys: - - dependencies-win-{{ checksum "scripts/install_deps.ps1" }} + - dependencies-win-{{ arch }}-{{ checksum "scripts/install_deps.ps1" }} # DO NOT EDIT between here and save_cache, but rather edit .\scripts\install_deps.ps1 # WARNING! If you do edit anything here instead, remember to invalidate the cache manually. - run: name: "Installing dependencies" command: .\scripts\install_deps.ps1 - save_cache: - key: dependencies-win-{{ checksum "scripts/install_deps.ps1" }} + key: dependencies-win-{{ arch }}-{{ checksum "scripts/install_deps.ps1" }} paths: - .\deps - run: diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index b2f4b4e10..ed11f2491 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -52,9 +52,6 @@ function validate_checksum { if [ ! -f /usr/local/lib/libz3.a ] # if this file does not exists (cache was not restored), rebuild dependencies then - git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow - git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow - brew update brew unlink python brew install boost brew install cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6014cc6fa..23c2f0e42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ include(EthCcache) # Let's find our dependencies include(EthDependencies) +include(fmtlib) include(jsoncpp) include(range-v3) include_directories(SYSTEM ${JSONCPP_INCLUDE_DIR}) diff --git a/Changelog.md b/Changelog.md index cfa19ed15..c77facc1f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,12 +13,21 @@ Language Features: Compiler Features: + * Commandline Interface: Accept nested brackets in step sequences passed to ``--yul-optimizations``. + * Commandline Interface: Add ``--debug-info`` option for selecting how much extra debug information should be included in the produced EVM assembly and Yul code. * SMTChecker: Output values for ``block.*``, ``msg.*`` and ``tx.*`` variables that are present in the called functions. + * Standard JSON: Accept nested brackets in step sequences passed to ``settings.optimizer.details.yulDetails.optimizerSteps``. + * Standard JSON: Add ``settings.debug.debugInfo`` option for selecting how much extra debug information should be included in the produced EVM assembly and Yul code. Bugfixes: + * Code Generator: Fix constructor source mappings for immutables. * Commandline Interface: Fix extra newline character being appended to sources passed through standard input, affecting their hashes. + * Commandline Interface: Report output selection options unsupported by the selected input mode instead of ignoring them. + * Commandline Interface: Don't return zero exit code when writing linked files to disk fails. * SMTChecker: Fix internal error in magic type access (``block``, ``msg``, ``tx``). + * TypeChecker: Fix internal error when using user defined value types in public library functions. + * Yul IR Generator: Do not output empty switches/if-bodies for empty contracts. diff --git a/cmake/fmtlib.cmake b/cmake/fmtlib.cmake new file mode 100644 index 000000000..5ed196cea --- /dev/null +++ b/cmake/fmtlib.cmake @@ -0,0 +1,20 @@ +include(FetchContent) + +FetchContent_Declare( + fmtlib + PREFIX "${CMAKE_BINARY_DIR}/deps" + DOWNLOAD_DIR "${CMAKE_SOURCE_DIR}/deps/downloads" + DOWNLOAD_NAME fmt-8.0.1.tar.gz + URL https://github.com/fmtlib/fmt/archive/8.0.1.tar.gz + URL_HASH SHA256=b06ca3130158c625848f3fb7418f235155a4d389b2abc3a6245fb01cb0eb1e01 +) + +if (CMAKE_VERSION VERSION_LESS "3.14.0") + FetchContent_GetProperties(fmtlib) + if (NOT fmtlib_POPULATED) + FetchContent_Populate(fmtlib) + add_subdirectory(${fmtlib_SOURCE_DIR} ${fmtlib_BINARY_DIR}) + endif() +else() + FetchContent_MakeAvailable(fmtlib) +endif() diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css index fd5062036..4ff53f3a7 100644 --- a/docs/_static/css/custom.css +++ b/docs/_static/css/custom.css @@ -1,14 +1,86 @@ pre { - white-space: pre-wrap; /* css-3 */ - white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ - white-space: -pre-wrap; /* Opera 4-6 */ - white-space: -o-pre-wrap; /* Opera 7 */ - word-wrap: break-word; + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; } .wy-table-responsive table td, .wy-table-responsive table th { - white-space: normal; + white-space: normal; } .rst-content table.docutils td { - vertical-align: top; + vertical-align: top; +} + +/* links */ +.rst-content a:not(:visited) { + color: #002fa7; +} + +.rst-content .highlighted { + background: #eac545; +} + +/* code block highlights */ +.rst-content pre { + background: #fafafa; +} + +.wy-side-nav-search img.logo { + width: 100px !important; + padding: 0; +} + +.wy-side-nav-search > a { + padding: 0; + margin: 0; +} + +/* project version (displayed under project logo) */ +.wy-side-nav-search .version { + color: #272525 !important; +} + +/* menu section headers */ +.wy-menu .caption { + color: #65afff !important; +} + +/* Link to Remix IDE shown next to code snippets */ +p.remix-link-container { + position: relative; + right: -100%; /* Positioned next to the the top-right corner of the code block following it. */ +} + +a.remix-link { + position: absolute; /* Remove it from normal flow not to affect the original position of the snippet. */ + top: 0.5em; + width: 3.236em; /* Size of the margin (= right-side padding in .wy-nav-content in the current theme). */ +} + +a.remix-link .link-icon { + background: url("../img/solid-share-arrow.svg") no-repeat; + display: block; + width: 1.5em; + height: 1.5em; + margin: auto; +} + +a.remix-link .link-text { + display: none; /* Visible only on hover. */ + width: 3.3em; /* Narrow enough to get two lines of text. */ + margin: auto; + text-align: center; + font-size: 0.8em; + line-height: normal; + color: black; +} + +a.remix-link:hover { + opacity: 0.5; +} + +a.remix-link:hover .link-text { + display: block; } diff --git a/docs/_static/css/dark.css b/docs/_static/css/dark.css index f9b445898..a87ff09eb 100644 --- a/docs/_static/css/dark.css +++ b/docs/_static/css/dark.css @@ -1,11 +1,9 @@ /* links */ -a, -a:visited { - color: #aaddff; +.rst-content a:not(:visited) { + color: #aaddff !important; } - /* code directives */ .method dt, @@ -46,6 +44,9 @@ em.property { background-color: #5a5a5a; } +.rst-content pre { + background: none; +} /* inlined code highlights */ @@ -70,6 +71,12 @@ code.docutils.literal.notranslate { color: #ddd; } +/* highlight color search text */ + +.rst-content .highlighted { + background: #ff5722; + box-shadow: 0 0 0 2px #f0978b; +} /* notes, warnings, hints */ @@ -619,4 +626,10 @@ code.docutils.literal.notranslate { } -/* Literal.Number.Integer.Long */ \ No newline at end of file +/* Literal.Number.Integer.Long */ + + +/* Link to Remix IDE shown over code snippets */ +a.remix-link { + filter: invert(1); /* The icon is black. In dark mode we want it white. */ +} diff --git a/docs/_static/css/toggle.css b/docs/_static/css/toggle.css index ebbd0658a..add134f6c 100644 --- a/docs/_static/css/toggle.css +++ b/docs/_static/css/toggle.css @@ -74,4 +74,10 @@ html.transition *:before, html.transition *:after { transition: ease-in-out 200ms !important; transition-delay: 0 !important; -} \ No newline at end of file +} + +nav.wy-nav-side { + /* The default padding of 2em is too small and the "Keyword Index" link gets obscured + * by the version toggle. */ + padding-bottom: 3em; +} diff --git a/docs/_static/img/solid-share-arrow.svg b/docs/_static/img/solid-share-arrow.svg new file mode 100644 index 000000000..1a1e61004 --- /dev/null +++ b/docs/_static/img/solid-share-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_templates/footer.html b/docs/_templates/footer.html new file mode 100644 index 000000000..59c7d7581 --- /dev/null +++ b/docs/_templates/footer.html @@ -0,0 +1,7 @@ +{% extends "!footer.html" %} + +{% block extrafooter %} +

+ Credits and attribution. +

+{% endblock %} diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index 5f81b2320..498c0e6e9 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -1,6 +1,10 @@ {% extends "!layout.html" %} - {% block menu %} +{% block menu %} {{ super() }} - Keyword Index - {% endblock %} + +{% endblock %} diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index 4ff9118bc..d36a96360 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -130,6 +130,12 @@ Global Variables - ``type(T).min`` (``T``): the minimum value representable by the integer type ``T``, see :ref:`Type Information`. - ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information`. +.. note:: + When contracts are evaluated off-chain rather than in context of a transaction included in a + block, you should not assume that ``block.*`` and ``tx.*`` refer to values from any specific + block or transaction. These values are provided by the EVM implementation that executes the + contract and can be arbitrary. + .. note:: Do not rely on ``block.timestamp`` or ``blockhash`` as a source of randomness, unless you know what you are doing. diff --git a/docs/conf.py b/docs/conf.py index 60d50fe51..b75eb966d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,6 +44,7 @@ def setup(sphinx): extensions = [ 'sphinx_a4doc', 'html_extra_template_renderer', + 'remix_code_links', ] a4_base_path = os.path.dirname(__file__) + '/grammar' @@ -128,7 +129,11 @@ html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +html_theme_options = { + 'logo_only': True, + 'style_nav_header_background': '#65afff', + 'display_version': True, +} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] @@ -142,7 +147,7 @@ html_theme = 'sphinx_rtd_theme' # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = "logo.svg" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -238,7 +243,7 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'solidity.tex', 'Solidity Documentation', 'Ethereum', 'manual'), + ('index', 'solidity.tex', 'Solidity Documentation', 'Ethereum', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/docs/contributing.rst b/docs/contributing.rst index 6b2db9546..ffb1d345c 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -86,12 +86,10 @@ Running the Compiler Tests Prerequisites ------------- -Some tests require the `evmone `_ -library, others require `libz3 `_. The test script -tries to discover the location of the ``evmone`` library, which can be located -in the current directory, installed on the system level, or the ``deps`` folder -in the project top level. The required file is called ``libevmone.so`` on Linux -systems, ``evmone.dll`` on Windows systems and ``libevmone.dylib`` on macOS. +For running all compiler tests you may want to optionally install a few +dependencies (`evmone `_, +`libz3 `_, and +`libhera `_). On macOS some of the testing scripts expect GNU coreutils to be installed. This can be easiest accomplished using Homebrew: ``brew install coreutils``. @@ -108,13 +106,28 @@ including those bundled into the `Boost C++ Test Framework `_ -and place it in the project root path or inside the ``deps`` folder. +The test system automatically tries to discover the location of +the `evmone `_ for running the semantic tests. + +The ``evmone`` library must be located in the ``deps`` or ``deps/lib`` directory relative to the +current working directory, to its parent or its parent's parent. Alternatively an explicit location +for the ``evmone`` shared object can be specified via the ``ETH_EVMONE`` environment variable. + +``evmone`` is needed mainly for running semantic and gas tests. +If you do not have it installed, you can skip these tests by passing the ``--no-semantic-tests`` +flag to ``scripts/soltest.sh``. + +Running Ewasm tests is disabled by default and can be explicitly enabled +via ``./scripts/soltest.sh --ewasm`` and requires `hera `_ +to be found by ``soltest``. +The mechanism for locating the ``hera`` library is the same as for ``evmone``, except that the +variable for specifying an explicit location is called ``ETH_HERA``. + +The ``evmone`` and ``hera`` libraries should both end with the file name +extension ``.so`` on Linux, ``.dll`` on Windows systems and ``.dylib`` on macOS. + +For running SMT tests, the ``libz3`` library must be installed and locatable +by ``cmake`` during compiler configure stage. If the ``libz3`` library is not installed on your system, you should disable the SMT tests by exporting ``SMT_FLAGS=--no-smt`` before running ``./scripts/tests.sh`` or diff --git a/docs/credits-and-attribution.rst b/docs/credits-and-attribution.rst new file mode 100644 index 000000000..f1aa6cfd3 --- /dev/null +++ b/docs/credits-and-attribution.rst @@ -0,0 +1,21 @@ +.. This page is meant to be linked to from the footer. + +:orphan: + +####################### +Credits and Attribution +####################### + +Website icons +============= + +.. |icon-share-solid| image:: _static/img/solid-share-arrow.svg +.. _share icon: https://fontawesome.com/v5.15/icons/share?style=solid +.. _Font Awesome Free License: https://fontawesome.com/license/free + ++-------------------------+-----------------------------------------------------------------------+ +| Icon | Attribution | ++=========================+=======================================================================+ +| |icon-share-solid| | - Source: `share icon`_ from Font Awesome 5.15.0. | +| | - License: `Font Awesome Free License`_ (CC BY 4.0). | ++-------------------------+-----------------------------------------------------------------------+ diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index b1d963ee5..3383e6195 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -11,7 +11,7 @@ sign and verify signatures, and setup the payment channel. Creating and verifying signatures ================================= -Imagine Alice wants to send a quantity of Ether to Bob, i.e. +Imagine Alice wants to send some Ether to Bob, i.e. Alice is the sender and Bob is the recipient. Alice only needs to send cryptographically signed messages off-chain diff --git a/docs/ext/remix_code_links.py b/docs/ext/remix_code_links.py new file mode 100644 index 000000000..2fc15ddda --- /dev/null +++ b/docs/ext/remix_code_links.py @@ -0,0 +1,83 @@ +import base64 +import docutils # pragma pylint: disable=import-error + +from sphinx.util import logging # pragma pylint: disable=import-error + +# NOTE: 2000 should generally be safe for all browsers, while 8000 for most of them. +MAX_SAFE_URL_LENGTH = 10000 + +logger = logging.getLogger(__name__) + + +def insert_node_before(child, new_sibling): + assert child in child.parent.children + + for position, node in enumerate(child.parent.children): + if node == child: + child.parent.insert(position, new_sibling) + break + + +def remix_code_url(source_code, language, solidity_version): + # NOTE: base64 encoded data may contain +, = and / characters. Remix seems to handle them just + # fine without any escaping. + base64_encoded_source = base64.b64encode(source_code.encode('utf-8')).decode('ascii') + return f"https://remix.ethereum.org/?language={language}&version={solidity_version}&code={base64_encoded_source}" + + +def build_remix_link_node(url): + link_icon_node = docutils.nodes.inline() + link_icon_node.set_class('link-icon') + + link_text_node = docutils.nodes.inline(text="open in Remix") + link_text_node.set_class('link-text') + + reference_node = docutils.nodes.reference('', '', internal=False, refuri=url) + reference_node.set_class('remix-link') + reference_node += [link_icon_node, link_text_node] + + paragraph_node = docutils.nodes.paragraph() + paragraph_node.set_class('remix-link-container') + paragraph_node += reference_node + return paragraph_node + + +def insert_remix_link(app, doctree, solidity_version): + if app.builder.format != 'html' or app.builder.name == 'epub': + return + + for literal_block_node in doctree.traverse(docutils.nodes.literal_block): + assert 'language' in literal_block_node.attributes + language = literal_block_node.attributes['language'].lower() + if language in ['solidity', 'yul']: + text_nodes = list(literal_block_node.traverse(docutils.nodes.Text)) + assert len(text_nodes) == 1 + + remix_url = remix_code_url(text_nodes[0], language, solidity_version) + url_length = len(remix_url.encode('utf-8')) + if url_length > MAX_SAFE_URL_LENGTH: + logger.warning( + "Remix URL generated from the code snippet exceeds the maximum safe URL length " + " (%d > %d bytes).", + url_length, + MAX_SAFE_URL_LENGTH, + location=(literal_block_node.source, literal_block_node.line), + ) + + insert_node_before(literal_block_node, build_remix_link_node(remix_url)) + + +def setup(app): + # NOTE: Need to access _raw_config here because setup() runs before app.config is ready. + solidity_version = app.config._raw_config['version'] # pylint: disable=protected-access + + app.connect( + 'doctree-resolved', + lambda app, doctree, docname: insert_remix_link(app, doctree, solidity_version) + ) + + return { + 'version': solidity_version, + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/docs/index.rst b/docs/index.rst index 44ddbff83..b8a830e0c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,11 +1,6 @@ Solidity ======== -.. image:: logo.svg - :width: 120px - :alt: Solidity logo - :align: center - Solidity is an object-oriented, high-level language for implementing smart contracts. Smart contracts are programs which govern the behaviour of accounts within the Ethereum state. @@ -22,8 +17,10 @@ With Solidity you can create contracts for uses such as voting, crowdfunding, bl 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 +version of Solidity. Apart from exceptional cases, only the latest version receives +`security fixes`. +Furthermore, breaking changes as well as +new features are introduced regularly. We currently use a 0.x version number `to indicate this fast pace of change `_. .. warning:: diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index e5de8a197..93179c041 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -275,7 +275,7 @@ The following transformation steps are the main components: - Common Subexpression Eliminator - Expression Simplifier - Redundant Assign Eliminator -- Full Function Inliner +- Full Inliner Optimizer Steps --------------- @@ -297,7 +297,8 @@ on the individual steps and their sequence below. - :ref:`for-loop-condition-into-body`. - :ref:`for-loop-condition-out-of-body`. - :ref:`for-loop-init-rewriter`. -- :ref:`functional-inliner`. +- :ref:`expression-inliner`. +- :ref:`full-inliner`. - :ref:`function-grouper`. - :ref:`function-hoister`. - :ref:`function-specializer`. @@ -1082,9 +1083,9 @@ The actual removal of the function is performed by the Unused Pruner. Function Inlining ----------------- -.. _functional-inliner: +.. _expression-inliner: -FunctionalInliner +ExpressionInliner ^^^^^^^^^^^^^^^^^ This component of the optimizer performs restricted function inlining by inlining functions that can be @@ -1107,12 +1108,12 @@ The result of this inlining is always a single expression. This component can only be used on sources with unique names. -.. _full-function-inliner: +.. _full-inliner: -FullFunctionInliner -^^^^^^^^^^^^^^^^^^^ +FullInliner +^^^^^^^^^^^ -The Full Function Inliner replaces certain calls of certain functions +The Full Inliner replaces certain calls of certain functions by the function's body. This is not very helpful in most cases, because it just increases the code size but does not have a benefit. Furthermore, code is usually very expensive and we would often rather have shorter diff --git a/docs/internals/source_mappings.rst b/docs/internals/source_mappings.rst index fbb84e2d1..11027b8ac 100644 --- a/docs/internals/source_mappings.rst +++ b/docs/internals/source_mappings.rst @@ -64,3 +64,7 @@ This means the following source mappings represent the same information: ``1:2:1;1:9:1;2:1:2;2:1:2;2:1:2`` ``1:2:1;:9;2:1:2;;`` + +Important to note is that when the :ref:`verbatim ` builtin is used, +the source mappings will be invalid: The builtin is considered a single +instruction instead of potentially multiple. diff --git a/docs/internals/variable_cleanup.rst b/docs/internals/variable_cleanup.rst index 1718fc66b..9fec6929f 100644 --- a/docs/internals/variable_cleanup.rst +++ b/docs/internals/variable_cleanup.rst @@ -14,7 +14,12 @@ hashes or sent as the data of a message call. Similarly, before storing a value in the storage, the remaining bits need to be cleaned because otherwise the garbled value can be observed. -On the other hand, we do not clean the bits if the immediately +Note that access via inline assembly is not considered such an operation: +If you use inline assembly to access Solidity variables +shorter than 256 bits, the compiler does not guarantee that +the value is properly cleaned up. + +Moreover, we do not clean the bits if the immediately following operation is not affected. For instance, since any non-zero value is considered ``true`` by ``JUMPI`` instruction, we do not clean the boolean values before they are used as the condition for diff --git a/docs/ir/ir-breaking-changes.rst b/docs/ir/ir-breaking-changes.rst index 9223b3763..8afbc58c3 100644 --- a/docs/ir/ir-breaking-changes.rst +++ b/docs/ir/ir-breaking-changes.rst @@ -1,3 +1,6 @@ + +.. index: ir breaking changes + ********************************* Solidity IR-based Codegen Changes ********************************* @@ -35,13 +38,15 @@ hiding new and different behavior in existing code. We have the same behavior for implicit delete, for example when array of structs is shortened. -- Function modifiers are implemented in a slightly different way regarding function parameters. +- Function modifiers are implemented in a slightly different way regarding function parameters and return variables. This especially has an effect if the placeholder ``_;`` is evaluated multiple times in a modifier. - In the old code generator, each function parameter has a fixed slot on the stack. If the function - is run multiple times because ``_;`` is used multiple times or used in a loop, then a change to the - function parameter's value is visible in the next execution of the function. + In the old code generator, each function parameter and return variable has a fixed slot on the stack. + If the function is run multiple times because ``_;`` is used multiple times or used in a loop, then a + change to the function parameter's or return variable's value is visible in the next execution of the function. The new code generator implements modifiers using actual functions and passes function parameters on. - This means that multiple executions of a function will get the same values for the parameters. + This means that multiple evaluations of a function's body will get the same values for the parameters, + and the effect on return variables is that they are reset to their default (zero) value for each + execution. .. code-block:: solidity @@ -57,6 +62,35 @@ hiding new and different behavior in existing code. If you execute ``f(0)`` in the old code generator, it will return ``2``, while it will return ``1`` when using the new code generator. + .. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.7.1 <0.9.0; + + contract C { + bool active = true; + modifier mod() + { + _; + active = false; + _; + } + function foo() external mod() returns (uint ret) + { + if (active) + ret = 1; // Same as ``return 1`` + } + } + + The function ``C.foo()`` returns the following values: + + - Old code generator: ``1`` as the return variable is initialized to ``0`` only once before the first ``_;`` + evaluation and then overwritten by the ``return 1;``. It is not initialized again for the second ``_;`` + evaluation and ``foo()`` does not explicitly assign it either (due to ``active == false``), thus it keeps + its first value. + - New code generator: ``0`` as all parameters, including return parameters, will be re-initialized before + each ``_;`` evaluation. + - The order of contract initialization has changed in case of inheritance. The order used to be: diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 95438b85a..8a6173280 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -92,6 +92,12 @@ Block and Transaction Properties ``msg.value`` can change for every **external** function call. This includes calls to library functions. +.. note:: + When contracts are evaluated off-chain rather than in context of a transaction included in a + block, you should not assume that ``block.*`` and ``tx.*`` refer to values from any specific + block or transaction. These values are provided by the EVM implementation that executes the + contract and can be arbitrary. + .. note:: Do not rely on ``block.timestamp`` or ``blockhash`` as a source of randomness, unless you know what you are doing. diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 1b14187ca..88da5d5e6 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -308,7 +308,18 @@ Input Description // "strip" removes all revert strings (if possible, i.e. if literals are used) keeping side-effects // "debug" injects strings for compiler-generated internal reverts, implemented for ABI encoders V1 and V2 for now. // "verboseDebug" even appends further information to user-supplied revert strings (not yet implemented) - "revertStrings": "default" + "revertStrings": "default", + // Optional: How much extra debug information to include in comments in the produced EVM + // assembly and Yul code. Available components are: + // - `location`: Annotations of the form `@src ::` indicating the + // location of the corresponding element in the original Solidity file, where: + // - `` is the file index matching the `@use-src` annotation, + // - `` is the index of the first byte at that location, + // - `` is the index of the first byte after that location. + // - `snippet`: A single-line code snippet from the location indicated by `@src`. + // The snippet is quoted and follows the corresponding `@src` annotation. + // - `*`: Wildcard value that can be used to request everything. + "debugInfo": ["location", "snippet"] }, // Metadata settings (optional) "metadata": { diff --git a/docs/yul.rst b/docs/yul.rst index e4819ff22..433f175f0 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1002,6 +1002,8 @@ within one Yul subobject. If at least one ``memoryguard`` call is found in a sub the additional optimiser steps will be run on it. +.. _yul-verbatim: + verbatim ^^^^^^^^ @@ -1263,6 +1265,7 @@ Abbreviation Full name ``a`` ``SSATransform`` ``t`` ``StructuralSimplifier`` ``u`` ``UnusedPruner`` +``p`` ``UnusedFunctionParameterPruner`` ``d`` ``VarDeclInitializer`` ============ =============================== diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 7884dd191..12c7be230 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -48,11 +48,11 @@ using namespace solidity::evmasm; using namespace solidity::langutil; using namespace solidity::util; -AssemblyItem const& Assembly::append(AssemblyItem const& _i) +AssemblyItem const& Assembly::append(AssemblyItem _i) { assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow."); m_deposit += static_cast(_i.deposit()); - m_items.emplace_back(_i); + m_items.emplace_back(move(_i)); if (!m_items.back().location().isValid() && m_currentSourceLocation.isValid()) m_items.back().setLocation(m_currentSourceLocation); m_items.back().m_modifierDepth = m_currentModifierDepth; @@ -68,7 +68,7 @@ unsigned Assembly::codeSize(unsigned subTagSize) const ret += i.second.size(); for (AssemblyItem const& i: m_items) - ret += i.bytesRequired(tagSize); + ret += i.bytesRequired(tagSize, Precision::Approximate); if (numberEncodingSize(ret) <= tagSize) return static_cast(ret); } @@ -96,13 +96,13 @@ public: m_out(_out), m_prefix(_prefix), m_sourceCodes(_sourceCodes), m_assembly(_assembly) {} - void feed(AssemblyItem const& _item) + void feed(AssemblyItem const& _item, DebugInfoSelection const& _debugInfoSelection) { if (_item.location().isValid() && _item.location() != m_location) { flush(); m_location = _item.location(); - printLocation(); + printLocation(_debugInfoSelection); } string expression = _item.toAssemblyText(m_assembly); @@ -142,16 +142,29 @@ public: m_pending.clear(); } - void printLocation() + void printLocation(DebugInfoSelection const& _debugInfoSelection) { - if (!m_location.isValid()) + if (!m_location.isValid() || (!_debugInfoSelection.location && !_debugInfoSelection.snippet)) return; + m_out << m_prefix << " /*"; - if (m_location.sourceName) - m_out << " " + escapeAndQuoteString(*m_location.sourceName); - if (m_location.hasText()) - m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end); - m_out << " " << locationFromSources(m_sourceCodes, m_location); + + if (_debugInfoSelection.location) + { + if (m_location.sourceName) + m_out << " " + escapeAndQuoteString(*m_location.sourceName); + if (m_location.hasText()) + m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end); + } + + if (_debugInfoSelection.snippet) + { + if (_debugInfoSelection.location) + m_out << " "; + + m_out << locationFromSources(m_sourceCodes, m_location); + } + m_out << " */" << endl; } @@ -167,12 +180,17 @@ private: } -void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const +void Assembly::assemblyStream( + ostream& _out, + DebugInfoSelection const& _debugInfoSelection, + string const& _prefix, + StringMap const& _sourceCodes +) const { Functionalizer f(_out, _prefix, _sourceCodes, *this); for (auto const& i: m_items) - f.feed(i); + f.feed(i, _debugInfoSelection); f.flush(); if (!m_data.empty() || !m_subs.empty()) @@ -185,7 +203,7 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co for (size_t i = 0; i < m_subs.size(); ++i) { _out << endl << _prefix << "sub_" << i << ": assembly {\n"; - m_subs[i]->assemblyStream(_out, _prefix + " ", _sourceCodes); + m_subs[i]->assemblyStream(_out, _debugInfoSelection, _prefix + " ", _sourceCodes); _out << _prefix << "}" << endl; } } @@ -194,10 +212,13 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co _out << endl << _prefix << "auxdata: 0x" << util::toHex(m_auxiliaryData) << endl; } -string Assembly::assemblyString(StringMap const& _sourceCodes) const +string Assembly::assemblyString( + DebugInfoSelection const& _debugInfoSelection, + StringMap const& _sourceCodes +) const { ostringstream tmp; - assemblyStream(tmp, "", _sourceCodes); + assemblyStream(tmp, _debugInfoSelection, "", _sourceCodes); return tmp.str(); } @@ -675,8 +696,11 @@ LinkerObject const& Assembly::assemble() const break; case PushImmutable: ret.bytecode.push_back(static_cast(Instruction::PUSH32)); + // Maps keccak back to the "identifier" string of that immutable. ret.immutableReferences[i.data()].first = m_immutables.at(i.data()); + // Record the bytecode offset of the PUSH32 argument. ret.immutableReferences[i.data()].second.emplace_back(ret.bytecode.size()); + // Advance bytecode by 32 bytes (default initialized). ret.bytecode.resize(ret.bytecode.size() + 32); break; case VerbatimBytecode: @@ -684,6 +708,7 @@ LinkerObject const& Assembly::assemble() const break; case AssignImmutable: { + // Expect 2 elements on stack (source, dest_base) auto const& offsets = immutableReferencesBySub[i.data()].second; for (size_t i = 0; i < offsets.size(); ++i) { diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 1d91c2f90..f768ffe31 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -64,7 +65,7 @@ public: AssemblyItem newPushImmutable(std::string const& _identifier); AssemblyItem newImmutableAssignment(std::string const& _identifier); - AssemblyItem const& append(AssemblyItem const& _i); + AssemblyItem const& append(AssemblyItem _i); AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } template Assembly& operator<<(T const& _d) { append(_d); return *this; } @@ -142,10 +143,12 @@ public: /// Create a text representation of the assembly. std::string assemblyString( + langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), StringMap const& _sourceCodes = StringMap() ) const; void assemblyStream( std::ostream& _out, + langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), std::string const& _prefix = "", StringMap const& _sourceCodes = StringMap() ) const; diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index a34870eda..eeeadb3ef 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -65,7 +65,7 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag) setData(data); } -size_t AssemblyItem::bytesRequired(size_t _addressLength) const +size_t AssemblyItem::bytesRequired(size_t _addressLength, Precision _precision) const { switch (m_type) { @@ -87,10 +87,25 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const case PushImmutable: return 1 + 32; case AssignImmutable: - if (m_immutableOccurrences) - return 1 + (3 + 32) * *m_immutableOccurrences; + { + unsigned long immutableOccurrences = 0; + + // Skip exact immutables count if no precise count was requested + if (_precision == Precision::Approximate) + immutableOccurrences = 1; // Assume one immut. ref. else - return 1 + (3 + 32) * 1024; // 1024 occurrences are beyond the maximum code size anyways. + { + solAssert(m_immutableOccurrences, "No immutable references. `bytesRequired()` called before assembly()?"); + immutableOccurrences = m_immutableOccurrences.value(); + } + + if (immutableOccurrences != 0) + // (DUP DUP PUSH ADD MSTORE)* (PUSH ADD MSTORE) + return (immutableOccurrences - 1) * (5 + 32) + (3 + 32); + else + // POP POP + return 2; + } case VerbatimBytecode: return std::get<2>(*m_verbatimBytecode).size(); default: @@ -322,6 +337,26 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item) return _out; } +size_t AssemblyItem::opcodeCount() const noexcept +{ + switch (m_type) + { + case AssemblyItemType::AssignImmutable: + // Append empty items if this AssignImmutable was referenced more than once. + // For n immutable occurrences the first (n - 1) occurrences will + // generate 5 opcodes and the last will generate 3 opcodes, + // because it is reusing the 2 top-most elements on the stack. + solAssert(m_immutableOccurrences, ""); + + if (m_immutableOccurrences.value() != 0) + return (*m_immutableOccurrences - 1) * 5 + 3; + else + return 2; // two POP's + default: + return 1; + } +} + std::string AssemblyItem::computeSourceMapping( AssemblyItems const& _items, map const& _sourceIndicesMap @@ -334,6 +369,7 @@ std::string AssemblyItem::computeSourceMapping( int prevSourceIndex = -1; int prevModifierDepth = -1; char prevJump = 0; + for (auto const& item: _items) { if (!ret.empty()) @@ -402,6 +438,9 @@ std::string AssemblyItem::computeSourceMapping( } } + if (item.opcodeCount() > 1) + ret += string(item.opcodeCount() - 1, ';'); + prevStart = location.start; prevLength = length; prevSourceIndex = sourceIndex; diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index f1b2b5043..1cbfe768d 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -51,6 +52,8 @@ enum AssemblyItemType VerbatimBytecode ///< Contains data that is inserted into the bytecode code section without modification. }; +enum class Precision { Precise , Approximate }; + class Assembly; class AssemblyItem; using AssemblyItems = std::vector; @@ -147,7 +150,10 @@ public: /// @returns an upper bound for the number of bytes required by this item, assuming that /// the value of a jump tag takes @a _addressLength bytes. - size_t bytesRequired(size_t _addressLength) const; + /// @param _precision Whether to return a precise count (which involves + /// counting immutable references which are only set after + /// a call to `assemble()`) or an approx. count. + size_t bytesRequired(size_t _addressLength, Precision _precision = Precision::Precise) const; size_t arguments() const; size_t returnValues() const; size_t deposit() const { return returnValues() - arguments(); } @@ -169,9 +175,11 @@ public: size_t m_modifierDepth = 0; - void setImmutableOccurrences(size_t _n) const { m_immutableOccurrences = std::make_shared(_n); } + void setImmutableOccurrences(size_t _n) const { m_immutableOccurrences = _n; } private: + size_t opcodeCount() const noexcept; + AssemblyItemType m_type; Instruction m_instruction; ///< Only valid if m_type == Operation std::shared_ptr m_data; ///< Only valid if m_type != Operation @@ -184,14 +192,14 @@ private: /// e.g. PushSubSize, PushTag, PushSub, etc. mutable std::shared_ptr m_pushedValue; /// Number of PushImmutable's with the same hash. Only used for AssignImmutable. - mutable std::shared_ptr m_immutableOccurrences; + mutable std::optional m_immutableOccurrences; }; -inline size_t bytesRequired(AssemblyItems const& _items, size_t _addressLength) +inline size_t bytesRequired(AssemblyItems const& _items, size_t _addressLength, Precision _precision = Precision::Precise) { size_t size = 0; for (AssemblyItem const& item: _items) - size += item.bytesRequired(_addressLength); + size += item.bytesRequired(_addressLength, _precision); return size; } diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt index 5b3afcdb6..4e392aadd 100644 --- a/libevmasm/CMakeLists.txt +++ b/libevmasm/CMakeLists.txt @@ -38,4 +38,4 @@ set(sources ) add_library(evmasm ${sources}) -target_link_libraries(evmasm PUBLIC solutil) +target_link_libraries(evmasm PUBLIC solutil fmt::fmt-header-only) diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 6800baef3..a639bc6fc 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -103,7 +103,7 @@ bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items) { - return evmasm::bytesRequired(_items, 3); // assume 3 byte addresses + return evmasm::bytesRequired(_items, 3, Precision::Approximate); // assume 3 byte addresses } void ConstantOptimisationMethod::replaceConstants( diff --git a/libevmasm/Inliner.cpp b/libevmasm/Inliner.cpp index 8d95bdc3b..527e6ae38 100644 --- a/libevmasm/Inliner.cpp +++ b/libevmasm/Inliner.cpp @@ -63,7 +63,7 @@ template uint64_t codeSize(RangeType const& _itemRange) { return ranges::accumulate(_itemRange | ranges::views::transform( - [](auto const& _item) { return _item.bytesRequired(2); } + [](auto const& _item) { return _item.bytesRequired(2, Precision::Approximate); } ), 0u); } /// @returns the tag id, if @a _item is a PushTag or Tag into the current subassembly, nullopt otherwise. diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 0ee0b5efd..8e4a09fcc 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -388,6 +388,8 @@ size_t numberOfPops(AssemblyItems const& _items) bool PeepholeOptimiser::optimise() { + // Avoid referencing immutables too early by using approx. counting in bytesRequired() + auto const approx = evmasm::Precision::Approximate; OptimiserState state {m_items, 0, std::back_inserter(m_optimisedItems)}; while (state.i < m_items.size()) applyMethods( @@ -398,7 +400,7 @@ bool PeepholeOptimiser::optimise() ); if (m_optimisedItems.size() < m_items.size() || ( m_optimisedItems.size() == m_items.size() && ( - evmasm::bytesRequired(m_optimisedItems, 3) < evmasm::bytesRequired(m_items, 3) || + evmasm::bytesRequired(m_optimisedItems, 3, approx) < evmasm::bytesRequired(m_items, 3, approx) || numberOfPops(m_optimisedItems) > numberOfPops(m_items) ) )) diff --git a/liblangutil/CMakeLists.txt b/liblangutil/CMakeLists.txt index 96f2a23d8..626d2945a 100644 --- a/liblangutil/CMakeLists.txt +++ b/liblangutil/CMakeLists.txt @@ -3,6 +3,8 @@ set(sources Common.h CharStream.cpp CharStream.h + DebugInfoSelection.cpp + DebugInfoSelection.h ErrorReporter.cpp ErrorReporter.h EVMVersion.h @@ -29,4 +31,4 @@ set(sources ) add_library(langutil ${sources}) -target_link_libraries(langutil PUBLIC solutil) +target_link_libraries(langutil PUBLIC solutil fmt::fmt-header-only) diff --git a/liblangutil/DebugInfoSelection.cpp b/liblangutil/DebugInfoSelection.cpp new file mode 100644 index 000000000..6ff023c01 --- /dev/null +++ b/liblangutil/DebugInfoSelection.cpp @@ -0,0 +1,157 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +#include + +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::langutil; +using namespace solidity::util; + +DebugInfoSelection const DebugInfoSelection::All(bool _value) noexcept +{ + DebugInfoSelection result; + for (bool DebugInfoSelection::* member: componentMap() | ranges::views::values) + result.*member = _value; + return result; +} + +DebugInfoSelection const DebugInfoSelection::Only(bool DebugInfoSelection::* _member) noexcept +{ + DebugInfoSelection result{}; + result.*_member = true; + return result; +} + +optional DebugInfoSelection::fromString(string_view _input) +{ + // TODO: Make more stuff constexpr and make it a static_assert(). + solAssert(componentMap().count("all") == 0, ""); + solAssert(componentMap().count("none") == 0, ""); + + if (_input == "all") + return All(); + if (_input == "none") + return None(); + + return fromComponents(_input | ranges::views::split(',') | ranges::to>); +} + +optional DebugInfoSelection::fromComponents( + vector const& _componentNames, + bool _acceptWildcards +) +{ + solAssert(componentMap().count("*") == 0, ""); + + DebugInfoSelection selection; + for (auto const& component: _componentNames) + { + if (component == "*") + return (_acceptWildcards ? make_optional(DebugInfoSelection::All()) : nullopt); + + if (!selection.enable(component)) + return nullopt; + } + + return selection; +} + +bool DebugInfoSelection::enable(string _component) +{ + auto memberIt = componentMap().find(boost::trim_copy(_component)); + if (memberIt == componentMap().end()) + return false; + + this->*(memberIt->second) = true; + return true; +} + +bool DebugInfoSelection::any() const noexcept +{ + for (bool DebugInfoSelection::* member: componentMap() | ranges::views::values) + if (this->*member) + return true; + + return false; +} + +bool DebugInfoSelection::all() const noexcept +{ + for (bool DebugInfoSelection::* member: componentMap() | ranges::views::values) + if (!(this->*member)) + return false; + + return true; +} + +DebugInfoSelection& DebugInfoSelection::operator&=(DebugInfoSelection const& _other) +{ + for (bool DebugInfoSelection::* member: componentMap() | ranges::views::values) + this->*member &= _other.*member; + return *this; +} + +DebugInfoSelection& DebugInfoSelection::operator|=(DebugInfoSelection const& _other) +{ + for (bool DebugInfoSelection::* member: componentMap() | ranges::views::values) + this->*member |= _other.*member; + return *this; +} + +DebugInfoSelection DebugInfoSelection::operator&(DebugInfoSelection _other) const noexcept +{ + _other &= *this; + return _other; +} + +DebugInfoSelection DebugInfoSelection::operator|(DebugInfoSelection _other) const noexcept +{ + _other |= *this; + return _other; +} + +bool DebugInfoSelection::operator==(DebugInfoSelection const& _other) const noexcept +{ + for (bool DebugInfoSelection::* member: componentMap() | ranges::views::values) + if (this->*member != _other.*member) + return false; + return true; +} + +ostream& langutil::operator<<(ostream& _stream, DebugInfoSelection const& _selection) +{ + vector selectedComponentNames; + for (auto const& [name, member]: _selection.componentMap()) + if (_selection.*member) + selectedComponentNames.push_back(name); + + return _stream << joinHumanReadable(selectedComponentNames, ","); +} diff --git a/liblangutil/DebugInfoSelection.h b/liblangutil/DebugInfoSelection.h new file mode 100644 index 000000000..40ba3d6b2 --- /dev/null +++ b/liblangutil/DebugInfoSelection.h @@ -0,0 +1,86 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Handles selections of debug info components. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace solidity::langutil +{ + +/** + * Represents a set of flags corresponding to components of debug info selected for some purpose. + * + * Provides extra functionality for enumerating the components and serializing/deserializing the + * selection to/from a comma-separated string. + */ +struct DebugInfoSelection +{ + static DebugInfoSelection const All(bool _value = true) noexcept; + static DebugInfoSelection const None() noexcept { return All(false); } + static DebugInfoSelection const Only(bool DebugInfoSelection::* _member) noexcept; + static DebugInfoSelection const Default() noexcept { return All(); } + + static std::optional fromString(std::string_view _input); + static std::optional fromComponents( + std::vector const& _componentNames, + bool _acceptWildcards = false + ); + bool enable(std::string _component); + + bool all() const noexcept; + bool any() const noexcept; + bool none() const noexcept { return !any(); } + bool only(bool DebugInfoSelection::* _member) const noexcept { return *this == Only(_member); } + + DebugInfoSelection& operator&=(DebugInfoSelection const& _other); + DebugInfoSelection& operator|=(DebugInfoSelection const& _other); + DebugInfoSelection operator&(DebugInfoSelection _other) const noexcept; + DebugInfoSelection operator|(DebugInfoSelection _other) const noexcept; + + bool operator!=(DebugInfoSelection const& _other) const noexcept { return !(*this == _other); } + bool operator==(DebugInfoSelection const& _other) const noexcept; + + friend std::ostream& operator<<(std::ostream& _stream, DebugInfoSelection const& _selection); + + static auto const& componentMap() + { + static std::map const components = { + {"location", &DebugInfoSelection::location}, + {"snippet", &DebugInfoSelection::snippet}, + {"ast-id", &DebugInfoSelection::astID}, + }; + return components; + } + + bool location = false; ///< Include source location. E.g. `@src 3:50:100` + bool snippet = false; ///< Include source code snippet next to location. E.g. `@src 3:50:100 "contract C {..."` + bool astID = false; ///< Include ID of the Solidity AST node. E.g. `@ast-id 15` +}; + +std::ostream& operator<<(std::ostream& _stream, DebugInfoSelection const& _selection); + +} diff --git a/liblangutil/SourceLocation.h b/liblangutil/SourceLocation.h index 66cef52fb..ea9958933 100644 --- a/liblangutil/SourceLocation.h +++ b/liblangutil/SourceLocation.h @@ -59,6 +59,13 @@ struct SourceLocation return start <= _other.start && _other.end <= end; } + bool containsOffset(int _pos) const + { + if (!hasText() || _pos < 0) + return false; + return start <= _pos && _pos < end; + } + bool intersects(SourceLocation const& _other) const { if (!hasText() || !_other.hasText() || !equalSources(_other)) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 24b7d2d85..a1cb68c35 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -159,4 +159,4 @@ set(sources ) add_library(solidity ${sources}) -target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost) +target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost fmt::fmt-header-only) diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 2d03aaf9c..ff8e2a29a 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -533,14 +533,14 @@ void ControlFlowBuilder::operator()(yul::FunctionCall const& _functionCall) yul::ASTWalker::operator()(_functionCall); if (auto const *builtinFunction = m_inlineAssembly->dialect().builtin(_functionCall.functionName.name)) - if (builtinFunction->controlFlowSideEffects.terminates) - { - if (builtinFunction->controlFlowSideEffects.reverts) - connect(m_currentNode, m_revertNode); - else - connect(m_currentNode, m_transactionReturnNode); + { + if (builtinFunction->controlFlowSideEffects.canTerminate) + connect(m_currentNode, m_transactionReturnNode); + if (builtinFunction->controlFlowSideEffects.canRevert) + connect(m_currentNode, m_revertNode); + if (!builtinFunction->controlFlowSideEffects.canContinue) m_currentNode = newLabel(); - } + } } void ControlFlowBuilder::operator()(yul::FunctionDefinition const&) diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index cdc8c8b7e..d08ee78b7 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -25,7 +25,6 @@ #include #include -#include #include using namespace std; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index c229252a8..b7d5db805 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -246,7 +246,10 @@ public: /// @returns the declared name. ASTString const& name() const { return *m_name; } + + /// @returns the location of the declared name itself or empty location if not available or unknown. SourceLocation const& nameLocation() const noexcept { return m_nameLocation; } + bool noVisibilitySpecified() const { return m_visibility == Visibility::Default; } Visibility visibility() const { return m_visibility == Visibility::Default ? defaultVisibility() : m_visibility; } bool isPublic() const { return visibility() >= Visibility::Public; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 9d0914682..a6e57a9ac 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -2563,6 +2562,11 @@ string UserDefinedValueType::toString(bool /* _short */) const return *definition().annotation().canonicalName; } +string UserDefinedValueType::canonicalName() const +{ + return *definition().annotation().canonicalName; +} + vector> UserDefinedValueType::makeStackItems() const { return underlyingType().stackItems(); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 2220875b1..334e69ba1 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1141,7 +1141,7 @@ public: } std::string toString(bool _short) const override; - std::string canonicalName() const override { solAssert(false, ""); } + std::string canonicalName() const override; std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); } protected: diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index 49a6be5e5..e75e5ef27 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -135,11 +135,15 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene { solAssert(_location.sourceName, ""); _context.markSourceUsed(*_location.sourceName); - return "/// " + AsmPrinter::formatSourceLocation( + + string debugInfo = AsmPrinter::formatSourceLocation( _location, _context.sourceIndices(), + _context.debugInfoSelection(), _context.soliditySourceProvider() ); + + return debugInfo.empty() ? "" : "/// " + debugInfo; } string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context) diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index fdc617220..cf01dc4f4 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -74,6 +75,7 @@ public: RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, std::map _sourceIndices, + langutil::DebugInfoSelection const& _debugInfoSelection, langutil::CharStreamProvider const* _soliditySourceProvider ): m_evmVersion(_evmVersion), @@ -81,6 +83,7 @@ public: m_revertStrings(_revertStrings), m_optimiserSettings(std::move(_optimiserSettings)), m_sourceIndices(std::move(_sourceIndices)), + m_debugInfoSelection(_debugInfoSelection), m_soliditySourceProvider(_soliditySourceProvider) {} @@ -174,6 +177,7 @@ public: bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); } + langutil::DebugInfoSelection debugInfoSelection() const { return m_debugInfoSelection; } langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; } private: @@ -220,6 +224,7 @@ private: std::set m_subObjects; + langutil::DebugInfoSelection m_debugInfoSelection = {}; langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; }; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index c1bfce4e3..44cd534ff 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -95,7 +95,12 @@ pair IRGenerator::run( { string const ir = yul::reindent(generate(_contract, _cborMetadata, _otherYulSources)); - yul::AssemblyStack asmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings); + yul::AssemblyStack asmStack( + m_evmVersion, + yul::AssemblyStack::Language::StrictAssembly, + m_optimiserSettings, + m_context.debugInfoSelection() + ); if (!asmStack.parseAndAnalyze("", ir)) { string errorMessage; @@ -340,8 +345,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) return m_context.functionCollector().createFunction(functionName, [&]() { m_context.resetLocalVariables(); Whiskers t(R"( - /// @ast-id - + function () -> { @@ -349,7 +353,10 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) )"); - t("astID", to_string(_function.id())); + if (m_context.debugInfoSelection().astID) + t("astIDComment", "/// @ast-id " + to_string(_function.id()) + "\n"); + else + t("astIDComment", ""); t("sourceLocationComment", dispenseLocationComment(_function)); t( "contractSourceLocationComment", @@ -409,8 +416,7 @@ string IRGenerator::generateModifier( return m_context.functionCollector().createFunction(functionName, [&]() { m_context.resetLocalVariables(); Whiskers t(R"( - /// @ast-id - + function () -> { @@ -418,6 +424,7 @@ string IRGenerator::generateModifier( } )"); + t("functionName", functionName); vector retParamsIn; for (auto const& varDecl: _function.returnParameters()) @@ -440,7 +447,11 @@ string IRGenerator::generateModifier( _modifierInvocation.name().annotation().referencedDeclaration ); solAssert(modifier, ""); - t("astID", to_string(modifier->id())); + + if (m_context.debugInfoSelection().astID) + t("astIDComment", "/// @ast-id " + to_string(modifier->id()) + "\n"); + else + t("astIDComment", ""); t("sourceLocationComment", dispenseLocationComment(*modifier)); t( "contractSourceLocationComment", @@ -546,14 +557,18 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) solAssert(paramTypes.empty(), ""); solUnimplementedAssert(type->sizeOnStack() == 1); return Whiskers(R"( - /// @ast-id - + function () -> rval { rval := loadimmutable("") } )") - ("astID", to_string(_varDecl.id())) + ( + "astIDComment", + m_context.debugInfoSelection().astID ? + "/// @ast-id " + to_string(_varDecl.id()) + "\n" : + "" + ) ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", @@ -567,14 +582,18 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) { solAssert(paramTypes.empty(), ""); return Whiskers(R"( - /// @ast-id - + function () -> { := () } )") - ("astID", to_string(_varDecl.id())) + ( + "astIDComment", + m_context.debugInfoSelection().astID ? + "/// @ast-id " + to_string(_varDecl.id()) + "\n" : + "" + ) ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", @@ -691,8 +710,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } return Whiskers(R"( - /// @ast-id - + function () -> { } @@ -702,7 +720,12 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) ("params", joinHumanReadable(parameters)) ("retVariables", joinHumanReadable(returnVariables)) ("code", std::move(code)) - ("astID", to_string(_varDecl.id())) + ( + "astIDComment", + m_context.debugInfoSelection().astID ? + "/// @ast-id " + to_string(_varDecl.id()) + "\n" : + "" + ) ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", @@ -829,7 +852,7 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract) for (ASTPointer const& varDecl: contract->constructor()->parameters()) params += m_context.addLocalVariable(*varDecl).stackSlots(); - if (contract->constructor()) + if (m_context.debugInfoSelection().astID && contract->constructor()) t("astIDComment", "/// @ast-id " + to_string(contract->constructor()->id()) + "\n"); else t("astIDComment", ""); @@ -944,7 +967,7 @@ string IRGenerator::callValueCheck() string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) { Whiskers t(R"X( - if iszero(lt(calldatasize(), 4)) + if iszero(lt(calldatasize(), 4)) { let selector := (calldataload(0)) switch selector @@ -962,8 +985,8 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) } default {} - } - if iszero(calldatasize()) { } + } + if iszero(calldatasize()) { } )X"); t("shr224", m_utils.shiftRightFunction(224)); @@ -1085,6 +1108,7 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices(), + m_context.debugInfoSelection(), m_context.soliditySourceProvider() ); newContext.copyFunctionIDsFrom(m_context); diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 85b570c7f..126f90046 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -49,6 +49,7 @@ public: RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, std::map _sourceIndices, + langutil::DebugInfoSelection const& _debugInfoSelection, langutil::CharStreamProvider const* _soliditySourceProvider ): m_evmVersion(_evmVersion), @@ -59,6 +60,7 @@ public: _revertStrings, std::move(_optimiserSettings), std::move(_sourceIndices), + _debugInfoSelection, _soliditySourceProvider ), m_utils(_evmVersion, m_context.revertStrings(), m_context.functionCollector()) diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index fc97ab0ca..f0072313b 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -991,7 +991,7 @@ void CHC::resetSourceAnalysis() if (usesZ3) { /// z3::fixedpoint does not have a reset mechanism, so we need to create another. - m_interface.reset(new Z3CHCInterface(m_settings.timeout)); + m_interface = std::make_unique(m_settings.timeout); auto z3Interface = dynamic_cast(m_interface.get()); solAssert(z3Interface, ""); m_context.setSolver(z3Interface->z3Interface()); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index e49c15387..9fa3cb164 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -201,7 +201,7 @@ void CompilerStack::findAndReportCyclicContractDependencies() void CompilerStack::setRemappings(vector _remappings) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set remappings before parsing.")); + solThrow(CompilerError, "Must set remappings before parsing."); for (auto const& remapping: _remappings) solAssert(!remapping.prefix.empty(), ""); m_importRemapper.setRemappings(move(_remappings)); @@ -210,28 +210,28 @@ void CompilerStack::setRemappings(vector _remappings) void CompilerStack::setViaIR(bool _viaIR) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set viaIR before parsing.")); + solThrow(CompilerError, "Must set viaIR before parsing."); m_viaIR = _viaIR; } void CompilerStack::setEVMVersion(langutil::EVMVersion _version) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set EVM version before parsing.")); + solThrow(CompilerError, "Must set EVM version before parsing."); m_evmVersion = _version; } void CompilerStack::setModelCheckerSettings(ModelCheckerSettings _settings) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set model checking settings before parsing.")); + solThrow(CompilerError, "Must set model checking settings before parsing."); m_modelCheckerSettings = _settings; } void CompilerStack::setLibraries(std::map const& _libraries) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set libraries before parsing.")); + solThrow(CompilerError, "Must set libraries before parsing."); m_libraries = _libraries; } @@ -245,14 +245,14 @@ void CompilerStack::setOptimiserSettings(bool _optimize, size_t _runs) void CompilerStack::setOptimiserSettings(OptimiserSettings _settings) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set optimiser settings before parsing.")); + solThrow(CompilerError, "Must set optimiser settings before parsing."); m_optimiserSettings = std::move(_settings); } void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set revert string settings before parsing.")); + solThrow(CompilerError, "Must set revert string settings before parsing."); solUnimplementedAssert(_revertStrings != RevertStrings::VerboseDebug); m_revertStrings = _revertStrings; } @@ -260,21 +260,28 @@ void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings) void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set use literal sources before parsing.")); + solThrow(CompilerError, "Must set use literal sources before parsing."); m_metadataLiteralSources = _metadataLiteralSources; } void CompilerStack::setMetadataHash(MetadataHash _metadataHash) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set metadata hash before parsing.")); + solThrow(CompilerError, "Must set metadata hash before parsing."); m_metadataHash = _metadataHash; } +void CompilerStack::selectDebugInfo(DebugInfoSelection _debugInfoSelection) +{ + if (m_stackState >= CompilationSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must select debug info components before compilation.")); + m_debugInfoSelection = _debugInfoSelection; +} + void CompilerStack::addSMTLib2Response(h256 const& _hash, string const& _response) { if (m_stackState >= ParsedAndImported) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must add SMTLib2 responses before parsing.")); + solThrow(CompilerError, "Must add SMTLib2 responses before parsing."); m_smtlib2Responses[_hash] = _response; } @@ -310,9 +317,9 @@ void CompilerStack::reset(bool _keepSettings) void CompilerStack::setSources(StringMap _sources) { if (m_stackState == SourcesSet) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Cannot change sources once set.")); + solThrow(CompilerError, "Cannot change sources once set."); if (m_stackState != Empty) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set sources before parsing.")); + solThrow(CompilerError, "Must set sources before parsing."); for (auto source: _sources) m_sources[source.first].charStream = make_unique(/*content*/std::move(source.second), /*name*/source.first); m_stackState = SourcesSet; @@ -321,7 +328,7 @@ void CompilerStack::setSources(StringMap _sources) bool CompilerStack::parse() { if (m_stackState != SourcesSet) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call parse only after the SourcesSet state.")); + solThrow(CompilerError, "Must call parse only after the SourcesSet state."); m_errorReporter.clear(); if (SemVerVersion{string(VersionString)}.isPrerelease()) @@ -369,7 +376,7 @@ bool CompilerStack::parse() void CompilerStack::importASTs(map const& _sources) { if (m_stackState != Empty) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call importASTs only before the SourcesSet state.")); + solThrow(CompilerError, "Must call importASTs only before the SourcesSet state."); m_sourceJsons = _sources; map> reconstructedSources = ASTJsonImporter(m_evmVersion).jsonToSourceUnit(m_sourceJsons); for (auto& src: reconstructedSources) @@ -392,7 +399,7 @@ void CompilerStack::importASTs(map const& _sources) bool CompilerStack::analyze() { if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed.")); + solThrow(CompilerError, "Must call analyze only after parsing was performed."); resolveImports(); for (Source const* source: m_sourceOrder) @@ -619,7 +626,7 @@ bool CompilerStack::compile(State _stopAfter) return true; if (m_hasError) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors.")); + solThrow(CompilerError, "Called compile with errors."); // Only compile contracts individually which have been requested. map> otherCompilers; @@ -691,7 +698,7 @@ void CompilerStack::link() vector CompilerStack::contractNames() const { if (m_stackState < Parsed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + solThrow(CompilerError, "Parsing was not successful."); vector contractNames; for (auto const& contract: m_contracts) contractNames.push_back(contract.first); @@ -701,7 +708,7 @@ vector CompilerStack::contractNames() const string const CompilerStack::lastContractName(optional const& _sourceName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + solThrow(CompilerError, "Parsing was not successful."); // try to find some user-supplied contract string contractName; for (auto const& it: m_sources) @@ -714,7 +721,7 @@ string const CompilerStack::lastContractName(optional const& _sourceName evmasm::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& currentContract = contract(_contractName); return currentContract.evmAssembly ? ¤tContract.evmAssembly->items() : nullptr; @@ -723,7 +730,7 @@ evmasm::AssemblyItems const* CompilerStack::assemblyItems(string const& _contrac evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& currentContract = contract(_contractName); return currentContract.evmRuntimeAssembly ? ¤tContract.evmRuntimeAssembly->items() : nullptr; @@ -732,7 +739,7 @@ evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _ Json::Value CompilerStack::generatedSources(string const& _contractName, bool _runtime) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& c = contract(_contractName); util::LazyInit const& sources = @@ -775,7 +782,7 @@ Json::Value CompilerStack::generatedSources(string const& _contractName, bool _r string const* CompilerStack::sourceMapping(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& c = contract(_contractName); if (!c.sourceMapping) @@ -789,7 +796,7 @@ string const* CompilerStack::sourceMapping(string const& _contractName) const string const* CompilerStack::runtimeSourceMapping(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& c = contract(_contractName); if (!c.runtimeSourceMapping) @@ -805,7 +812,7 @@ string const* CompilerStack::runtimeSourceMapping(string const& _contractName) c std::string const CompilerStack::filesystemFriendlyName(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found.")); + solThrow(CompilerError, "No compiled contracts found."); // Look up the contract (by its fully-qualified name) Contract const& matchContract = m_contracts.at(_contractName); @@ -829,7 +836,7 @@ std::string const CompilerStack::filesystemFriendlyName(string const& _contractN string const& CompilerStack::yulIR(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); return contract(_contractName).yulIR; } @@ -837,7 +844,7 @@ string const& CompilerStack::yulIR(string const& _contractName) const string const& CompilerStack::yulIROptimized(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); return contract(_contractName).yulIROptimized; } @@ -845,7 +852,7 @@ string const& CompilerStack::yulIROptimized(string const& _contractName) const string const& CompilerStack::ewasm(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); return contract(_contractName).ewasm; } @@ -853,7 +860,7 @@ string const& CompilerStack::ewasm(string const& _contractName) const evmasm::LinkerObject const& CompilerStack::ewasmObject(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); return contract(_contractName).ewasmObject; } @@ -861,7 +868,7 @@ evmasm::LinkerObject const& CompilerStack::ewasmObject(string const& _contractNa evmasm::LinkerObject const& CompilerStack::object(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); return contract(_contractName).object; } @@ -869,7 +876,7 @@ evmasm::LinkerObject const& CompilerStack::object(string const& _contractName) c evmasm::LinkerObject const& CompilerStack::runtimeObject(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); return contract(_contractName).runtimeObject; } @@ -878,11 +885,11 @@ evmasm::LinkerObject const& CompilerStack::runtimeObject(string const& _contract string CompilerStack::assemblyString(string const& _contractName, StringMap const& _sourceCodes) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& currentContract = contract(_contractName); if (currentContract.evmAssembly) - return currentContract.evmAssembly->assemblyString(_sourceCodes); + return currentContract.evmAssembly->assemblyString(m_debugInfoSelection, _sourceCodes); else return string(); } @@ -891,7 +898,7 @@ string CompilerStack::assemblyString(string const& _contractName, StringMap cons Json::Value CompilerStack::assemblyJSON(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); Contract const& currentContract = contract(_contractName); if (currentContract.evmAssembly) @@ -922,7 +929,7 @@ map CompilerStack::sourceIndices() const Json::Value const& CompilerStack::contractABI(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); return contractABI(contract(_contractName)); } @@ -930,7 +937,7 @@ Json::Value const& CompilerStack::contractABI(string const& _contractName) const Json::Value const& CompilerStack::contractABI(Contract const& _contract) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); solAssert(_contract.contract, ""); @@ -940,7 +947,7 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const Json::Value const& CompilerStack::storageLayout(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); return storageLayout(contract(_contractName)); } @@ -948,7 +955,7 @@ Json::Value const& CompilerStack::storageLayout(string const& _contractName) con Json::Value const& CompilerStack::storageLayout(Contract const& _contract) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); solAssert(_contract.contract, ""); @@ -958,7 +965,7 @@ Json::Value const& CompilerStack::storageLayout(Contract const& _contract) const Json::Value const& CompilerStack::natspecUser(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); return natspecUser(contract(_contractName)); } @@ -966,7 +973,7 @@ Json::Value const& CompilerStack::natspecUser(string const& _contractName) const Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); solAssert(_contract.contract, ""); @@ -976,7 +983,7 @@ Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const Json::Value const& CompilerStack::natspecDev(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); return natspecDev(contract(_contractName)); } @@ -984,7 +991,7 @@ Json::Value const& CompilerStack::natspecDev(string const& _contractName) const Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); solAssert(_contract.contract, ""); @@ -994,7 +1001,7 @@ Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); Json::Value methodIdentifiers(Json::objectValue); for (auto const& it: contractDefinition(_contractName).interfaceFunctions()) @@ -1005,7 +1012,7 @@ Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); return createCBORMetadata(contract(_contractName), _forIR); } @@ -1013,7 +1020,7 @@ bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) cons string const& CompilerStack::metadata(Contract const& _contract) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); solAssert(_contract.contract, ""); @@ -1023,7 +1030,7 @@ string const& CompilerStack::metadata(Contract const& _contract) const CharStream const& CompilerStack::charStream(string const& _sourceName) const { if (m_stackState < SourcesSet) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No sources set.")); + solThrow(CompilerError, "No sources set."); solAssert(source(_sourceName).charStream, ""); @@ -1033,9 +1040,9 @@ CharStream const& CompilerStack::charStream(string const& _sourceName) const SourceUnit const& CompilerStack::ast(string const& _sourceName) const { if (m_stackState < Parsed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing not yet performed.")); + solThrow(CompilerError, "Parsing not yet performed."); if (!source(_sourceName).ast && !m_parserErrorRecovery) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + solThrow(CompilerError, "Parsing was not successful."); return *source(_sourceName).ast; } @@ -1043,7 +1050,7 @@ SourceUnit const& CompilerStack::ast(string const& _sourceName) const ContractDefinition const& CompilerStack::contractDefinition(string const& _contractName) const { if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); + solThrow(CompilerError, "Analysis was not successful."); return *contract(_contractName).contract; } @@ -1054,7 +1061,7 @@ size_t CompilerStack::functionEntryPoint( ) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); for (auto&& [name, data]: contract(_contractName).runtimeObject.functionDebugData) if (data.sourceID == _function.id()) @@ -1256,7 +1263,7 @@ void CompilerStack::compileContract( solAssert(!m_viaIR, ""); solAssert(m_stackState >= AnalysisPerformed, ""); if (m_hasError) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors.")); + solThrow(CompilerError, "Called compile with errors."); if (_otherCompilers.count(&_contract)) return; @@ -1294,7 +1301,7 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) { solAssert(m_stackState >= AnalysisPerformed, ""); if (m_hasError) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateIR with errors.")); + solThrow(CompilerError, "Called generateIR with errors."); Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName()); if (!compiledContract.yulIR.empty()) @@ -1319,7 +1326,7 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) for (auto const& pair: m_contracts) otherYulSources.emplace(pair.second.contract, pair.second.yulIR); - IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), this); + IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), m_debugInfoSelection, this); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run( _contract, createCBORMetadata(compiledContract, /* _forIR */ true), @@ -1331,7 +1338,7 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) { solAssert(m_stackState >= AnalysisPerformed, ""); if (m_hasError) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEVMFromIR with errors.")); + solThrow(CompilerError, "Called generateEVMFromIR with errors."); if (!_contract.canBeDeployed()) return; @@ -1342,7 +1349,12 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) return; // Re-parse the Yul IR in EVM dialect - yul::AssemblyStack stack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings); + yul::AssemblyStack stack( + m_evmVersion, + yul::AssemblyStack::Language::StrictAssembly, + m_optimiserSettings, + m_debugInfoSelection + ); stack.parseAndAnalyze("", compiledContract.yulIROptimized); stack.optimize(); @@ -1358,7 +1370,7 @@ void CompilerStack::generateEwasm(ContractDefinition const& _contract) { solAssert(m_stackState >= AnalysisPerformed, ""); if (m_hasError) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called generateEwasm with errors.")); + solThrow(CompilerError, "Called generateEwasm with errors."); if (!_contract.canBeDeployed()) return; @@ -1369,7 +1381,12 @@ void CompilerStack::generateEwasm(ContractDefinition const& _contract) return; // Re-parse the Yul IR in EVM dialect - yul::AssemblyStack stack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings); + yul::AssemblyStack stack( + m_evmVersion, + yul::AssemblyStack::Language::StrictAssembly, + m_optimiserSettings, + m_debugInfoSelection + ); stack.parseAndAnalyze("", compiledContract.yulIROptimized); stack.optimize(); @@ -1412,14 +1429,14 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa } // If we get here, both lookup methods failed. - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract \"" + _contractName + "\" not found.")); + solThrow(CompilerError, "Contract \"" + _contractName + "\" not found."); } CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const { auto it = m_sources.find(_sourceName); if (it == m_sources.end()) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found.")); + solThrow(CompilerError, "Given source file not found."); return it->second; } @@ -1658,7 +1675,7 @@ Json::Value gasToJson(GasEstimator::GasConsumption const& _gas) Json::Value CompilerStack::gasEstimates(string const& _contractName) const { if (m_stackState != CompilationSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + solThrow(CompilerError, "Compilation was not successful."); if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName)) return Json::Value(); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index bbef4dc64..c97581a65 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -35,10 +35,11 @@ #include +#include +#include #include #include #include -#include #include @@ -203,6 +204,9 @@ public: /// @param _metadataHash can be IPFS, Bzzr1, None void setMetadataHash(MetadataHash _metadataHash); + /// Select components of debug info that should be included in comments in generated assembly. + void selectDebugInfo(langutil::DebugInfoSelection _debugInfoSelection); + /// Sets the sources. Must be set before parsing. void setSources(StringMap _sources); @@ -505,6 +509,7 @@ private: langutil::ErrorReporter m_errorReporter; bool m_metadataLiteralSources = false; MetadataHash m_metadataHash = MetadataHash::IPFS; + langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default(); bool m_parserErrorRecovery = false; State m_stackState = Empty; bool m_importedSources = false; diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 2a1859d21..cfd1feb33 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -104,10 +104,7 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so try { if (_kind != ReadCallback::kindString(ReadCallback::Kind::ReadFile)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment( - "ReadFile callback used as callback kind " + - _kind - )); + solAssert(false, "ReadFile callback used as callback kind " + _kind); string strippedSourceUnitName = _sourceUnitName; if (strippedSourceUnitName.find("file://") == 0) strippedSourceUnitName.erase(0, 7); @@ -171,7 +168,7 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so } catch (...) { - return ReadCallback::Result{false, "Unknown exception in read callback."}; + return ReadCallback::Result{false, "Unknown exception in read callback: " + boost::current_exception_diagnostic_information()}; } } diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index 578a5519a..5317acee4 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -44,20 +44,20 @@ struct OptimiserSettings static char constexpr DefaultYulOptimiserSteps[] = "dhfoDgvulfnTUtnIf" // None of these can make stack problems worse "[" - "xarrscLM" // Turn into SSA and simplify + "xa[r]scLM" // Turn into SSA and simplify "cCTUtTOntnfDIul" // Perform structural simplification "Lcul" // Simplify again - "Vcul jj" // Reverse SSA + "Vcul [j]" // Reverse SSA // should have good "compilability" property here. "Tpeul" // Run functional expression inliner - "xarulrul" // Prune a bit more in SSA - "xarrcL" // Turn into SSA again and simplify + "xa[rul]" // Prune a bit more in SSA + "xa[r]cL" // Turn into SSA again and simplify "gvif" // Run full inliner - "CTUcarrLsTFOtfDncarrIulc" // SSA plus simplify + "CTUca[r]LsTFOtfDnca[r]Iulc" // SSA plus simplify "]" - "jmuljuljul VcTOcul jmul"; // Make source short and pretty + "jmul[jul] VcTOcul jmul"; // Make source short and pretty /// No optimisations at all - not recommended. static OptimiserSettings none() diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 7d354a405..66f5dc4e5 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -28,9 +28,13 @@ #include #include #include -#include + #include + #include + +#include + #include #include #include @@ -793,7 +797,7 @@ std::variant StandardCompiler: if (settings.isMember("debug")) { - if (auto result = checkKeys(settings["debug"], {"revertStrings"}, "settings.debug")) + if (auto result = checkKeys(settings["debug"], {"revertStrings", "debugInfo"}, "settings.debug")) return *result; if (settings["debug"].isMember("revertStrings")) @@ -810,6 +814,31 @@ std::variant StandardCompiler: ); ret.revertStrings = *revertStrings; } + + if (settings["debug"].isMember("debugInfo")) + { + if (!settings["debug"]["debugInfo"].isArray()) + return formatFatalError("JSONError", "settings.debug.debugInfo must be an array."); + + vector components; + for (Json::Value const& arrayValue: settings["debug"]["debugInfo"]) + components.push_back(arrayValue.asString()); + + optional debugInfoSelection = DebugInfoSelection::fromComponents( + components, + true /* _acceptWildcards */ + ); + if (!debugInfoSelection.has_value()) + return formatFatalError("JSONError", "Invalid value in settings.debug.debugInfo."); + + if (debugInfoSelection->snippet && !debugInfoSelection->location) + return formatFatalError( + "JSONError", + "To use 'snippet' with settings.debug.debugInfo you must select also 'location'." + ); + + ret.debugInfoSelection = debugInfoSelection.value(); + } } if (settings.isMember("remappings") && !settings["remappings"].isArray()) @@ -1029,6 +1058,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting compilerStack.setRemappings(move(_inputsAndSettings.remappings)); compilerStack.setOptimiserSettings(std::move(_inputsAndSettings.optimiserSettings)); compilerStack.setRevertStringBehaviour(_inputsAndSettings.revertStrings); + if (_inputsAndSettings.debugInfoSelection.has_value()) + compilerStack.selectDebugInfo(_inputsAndSettings.debugInfoSelection.value()); compilerStack.setLibraries(_inputsAndSettings.libraries); compilerStack.useMetadataLiteralSources(_inputsAndSettings.metadataLiteralSources); compilerStack.setMetadataHash(_inputsAndSettings.metadataHash); @@ -1151,13 +1182,13 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting "Exception during compilation: " + boost::diagnostic_information(_exception) )); } - catch (std::exception const& _e) + catch (std::exception const& _exception) { errors.append(formatError( Error::Severity::Error, "Exception", "general", - "Unknown exception during compilation" + (_e.what() ? ": " + string(_e.what()) : ".") + "Unknown exception during compilation: " + boost::diagnostic_information(_exception) )); } catch (...) @@ -1166,7 +1197,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting Error::Severity::Error, "Exception", "general", - "Unknown exception during compilation." + "Unknown exception during compilation: " + boost::current_exception_diagnostic_information() )); } @@ -1358,7 +1389,10 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) AssemblyStack stack( _inputsAndSettings.evmVersion, AssemblyStack::Language::StrictAssembly, - _inputsAndSettings.optimiserSettings + _inputsAndSettings.optimiserSettings, + _inputsAndSettings.debugInfoSelection.has_value() ? + _inputsAndSettings.debugInfoSelection.value() : + DebugInfoSelection::Default() ); string const& sourceName = _inputsAndSettings.sources.begin()->first; string const& sourceContents = _inputsAndSettings.sources.begin()->second; @@ -1481,7 +1515,7 @@ Json::Value StandardCompiler::compile(Json::Value const& _input) noexcept } catch (...) { - return formatFatalError("InternalCompilerError", "Internal exception in StandardCompiler::compile"); + return formatFatalError("InternalCompilerError", "Internal exception in StandardCompiler::compile: " + boost::current_exception_diagnostic_information()); } } diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 4d43fdfec..679e731a2 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -26,6 +26,8 @@ #include #include +#include + #include #include #include @@ -78,6 +80,7 @@ private: std::vector remappings; RevertStrings revertStrings = RevertStrings::Default; OptimiserSettings optimiserSettings = OptimiserSettings::minimal(); + std::optional debugInfoSelection; std::map libraries; bool metadataLiteralSources = false; CompilerStack::MetadataHash metadataHash = CompilerStack::MetadataHash::IPFS; diff --git a/libsolutil/Assertions.h b/libsolutil/Assertions.h index f04e90a1f..81823e040 100644 --- a/libsolutil/Assertions.h +++ b/libsolutil/Assertions.h @@ -61,14 +61,9 @@ inline std::string stringOrDefault(std::string _string, std::string _defaultStri do \ { \ if (!(_condition)) \ - ::boost::throw_exception( \ - _exceptionType() << \ - ::solidity::util::errinfo_comment( \ - ::solidity::util::assertions::stringOrDefault(_description, _defaultDescription) \ - ) << \ - ::boost::throw_function(ETH_FUNC) << \ - ::boost::throw_file(__FILE__) << \ - ::boost::throw_line(__LINE__) \ + solThrow( \ + _exceptionType, \ + ::solidity::util::assertions::stringOrDefault(_description, _defaultDescription) \ ); \ } \ while (false) diff --git a/libsolutil/Exceptions.h b/libsolutil/Exceptions.h index 379221ab2..d83d8004b 100644 --- a/libsolutil/Exceptions.h +++ b/libsolutil/Exceptions.h @@ -43,6 +43,19 @@ struct Exception: virtual std::exception, virtual boost::exception private: }; +/// Throws an exception with a given description and extra information about the location the +/// exception was thrown from. +/// @param _exceptionType The type of the exception to throw (not an instance). +/// @param _description The message that describes the error. +#define solThrow(_exceptionType, _description) \ + ::boost::throw_exception( \ + _exceptionType() << \ + ::solidity::util::errinfo_comment(_description) << \ + ::boost::throw_function(ETH_FUNC) << \ + ::boost::throw_file(__FILE__) << \ + ::boost::throw_line(__LINE__) \ + ) + #define DEV_SIMPLE_EXCEPTION(X) struct X: virtual ::solidity::util::Exception { const char* what() const noexcept override { return #X; } } DEV_SIMPLE_EXCEPTION(InvalidAddress); diff --git a/libsolutil/Whiskers.cpp b/libsolutil/Whiskers.cpp index e236104c7..340527bdd 100644 --- a/libsolutil/Whiskers.cpp +++ b/libsolutil/Whiskers.cpp @@ -189,11 +189,13 @@ string Whiskers::replace( if (conditionName[0] == '+') { string tag = conditionName.substr(1); - assertThrow( - _parameters.count(tag), - WhiskersError, "Tag " + tag + " used as condition but was not set." - ); - conditionValue = !_parameters.at(tag).empty(); + + if (_parameters.count(tag)) + conditionValue = !_parameters.at(tag).empty(); + else if (_listParameters.count(tag)) + conditionValue = !_listParameters.at(tag).empty(); + else + assertThrow(false, WhiskersError, "Tag " + tag + " used as condition but was not set."); } else { diff --git a/libsolutil/Whiskers.h b/libsolutil/Whiskers.h index 113fbe6ed..7bbf74f09 100644 --- a/libsolutil/Whiskers.h +++ b/libsolutil/Whiskers.h @@ -60,12 +60,13 @@ DEV_SIMPLE_EXCEPTION(WhiskersError); * - Condition parameter: ......, where "" is optional * replaced (and recursively expanded) by the first part if the condition is true * and by the second (or empty string if missing) if the condition is false - * - Conditional string parameter: ...... - * Works similar to a conditional parameter where the checked condition is - * that the regular (string) parameter called "name" is non-empty. * - List parameter: <#list>... * The part between the tags is repeated as often as values are provided * in the mapping. Each list element can have its own parameter -> value mapping. + * - Conditional value parameter: ...... + * Works similar to a conditional parameter where the checked condition is + * that the string or list parameter called "name" is non-empty or contains + * no elements respectively. */ class Whiskers { diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index c2bdc42f7..342d3d456 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -37,6 +37,8 @@ #include +#include + #include #include @@ -618,7 +620,7 @@ void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _locati m_errorReporter.typeError( 5473_error, _location, - "\"" + _type.str() + "\" is not a valid type (user defined types are not yet supported)." + fmt::format("\"{}\" is not a valid type (user defined types are not yet supported).", _type) ); } @@ -628,11 +630,7 @@ void AsmAnalyzer::expectType(YulString _expectedType, YulString _givenType, Sour m_errorReporter.typeError( 3781_error, _location, - "Expected a value of type \"" + - _expectedType.str() + - "\" but got \"" + - _givenType.str() + - "\"" + fmt::format("Expected a value of type \"{}\" but got \"{}\".", _expectedType, _givenType) ); } @@ -664,14 +662,12 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio m_errorReporter.typeError( _errorId, _location, - "The \"" + - boost::to_lower_copy(instructionInfo(_instr).name) - + "\" instruction is " + - vmKindMessage + - " VMs " + - "(you are currently compiling for \"" + - m_evmVersion.name() + - "\")." + fmt::format( + "The \"{instruction}\" instruction is {kind} VMs (you are currently compiling for \"{version}\").", + fmt::arg("instruction", boost::to_lower_copy(instructionInfo(_instr).name)), + fmt::arg("kind", vmKindMessage), + fmt::arg("version", m_evmVersion.name()) + ) ); }; diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 68f21bcd7..46000bc10 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -261,10 +261,16 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const string AsmPrinter::formatSourceLocation( SourceLocation const& _location, map const& _nameToSourceIndex, + DebugInfoSelection const& _debugInfoSelection, CharStreamProvider const* _soliditySourceProvider ) { yulAssert(!_nameToSourceIndex.empty(), ""); + if (_debugInfoSelection.snippet) + yulAssert(_debugInfoSelection.location, "@src tag must always contain the source location"); + + if (_debugInfoSelection.none()) + return ""; string sourceIndex = "-1"; string solidityCodeSnippet = ""; @@ -272,7 +278,7 @@ string AsmPrinter::formatSourceLocation( { sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName)); - if (_soliditySourceProvider) + if (_debugInfoSelection.snippet && _soliditySourceProvider) { solidityCodeSnippet = escapeAndQuoteString( _soliditySourceProvider->charStream(*_location.sourceName).singleLineSnippet(_location) @@ -298,12 +304,13 @@ string AsmPrinter::formatSourceLocation( string AsmPrinter::formatDebugData(shared_ptr const& _debugData, bool _statement) { - if (!_debugData) + if (!_debugData || m_debugInfoSelection.none()) return ""; vector items; if (auto id = _debugData->astID) - items.emplace_back("@ast-id " + to_string(*id)); + if (m_debugInfoSelection.astID) + items.emplace_back("@ast-id " + to_string(*id)); if ( m_lastLocation != _debugData->originLocation && @@ -315,6 +322,7 @@ string AsmPrinter::formatDebugData(shared_ptr const& _debugData items.emplace_back(formatSourceLocation( _debugData->originLocation, m_nameToSourceIndex, + m_debugInfoSelection, m_soliditySourceProvider )); } diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 3bb683191..7c67c14ac 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -48,9 +49,11 @@ public: explicit AsmPrinter( Dialect const* _dialect = nullptr, std::optional>> _sourceIndexToName = {}, + langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), langutil::CharStreamProvider const* _soliditySourceProvider = nullptr ): m_dialect(_dialect), + m_debugInfoSelection(_debugInfoSelection), m_soliditySourceProvider(_soliditySourceProvider) { if (_sourceIndexToName) @@ -58,12 +61,12 @@ public: m_nameToSourceIndex[*name] = index; } - explicit AsmPrinter( Dialect const& _dialect, std::optional>> _sourceIndexToName = {}, + langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), langutil::CharStreamProvider const* _soliditySourceProvider = nullptr - ): AsmPrinter(&_dialect, _sourceIndexToName, _soliditySourceProvider) {} + ): AsmPrinter(&_dialect, _sourceIndexToName, _debugInfoSelection, _soliditySourceProvider) {} std::string operator()(Literal const& _literal); std::string operator()(Identifier const& _identifier); @@ -83,6 +86,7 @@ public: static std::string formatSourceLocation( langutil::SourceLocation const& _location, std::map const& _nameToSourceIndex, + langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr ); @@ -100,6 +104,7 @@ private: Dialect const* const m_dialect = nullptr; std::map m_nameToSourceIndex; langutil::SourceLocation m_lastLocation = {}; + langutil::DebugInfoSelection m_debugInfoSelection = {}; langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; }; diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 1ed55a2d6..30ad58d77 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -249,7 +249,7 @@ AssemblyStack::assembleWithDeployed(optional _deployName) const MachineAssemblyObject creationObject; creationObject.bytecode = make_shared(creationAssembly->assemble()); yulAssert(creationObject.bytecode->immutableReferences.empty(), "Leftover immutables."); - creationObject.assembly = creationAssembly->assemblyString(); + creationObject.assembly = creationAssembly->assemblyString(m_debugInfoSelection); creationObject.sourceMappings = make_unique( evmasm::AssemblyItem::computeSourceMapping( creationAssembly->items(), @@ -261,7 +261,7 @@ AssemblyStack::assembleWithDeployed(optional _deployName) const if (deployedAssembly) { deployedObject.bytecode = make_shared(deployedAssembly->assemble()); - deployedObject.assembly = deployedAssembly->assemblyString(); + deployedObject.assembly = deployedAssembly->assemblyString(m_debugInfoSelection); deployedObject.sourceMappings = make_unique( evmasm::AssemblyItem::computeSourceMapping( deployedAssembly->items(), @@ -314,11 +314,13 @@ AssemblyStack::assembleEVMWithDeployed(optional _deployName) const return {make_shared(assembly), {}}; } -string AssemblyStack::print(CharStreamProvider const* _soliditySourceProvider) const +string AssemblyStack::print( + CharStreamProvider const* _soliditySourceProvider +) const { yulAssert(m_parserResult, ""); yulAssert(m_parserResult->code, ""); - return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion), _soliditySourceProvider) + "\n"; + return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion), m_debugInfoSelection, _soliditySourceProvider) + "\n"; } shared_ptr AssemblyStack::parserResult() const diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index 91ca78af7..950265ca4 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -22,9 +22,10 @@ #pragma once +#include +#include #include #include -#include #include #include @@ -69,12 +70,24 @@ public: enum class Machine { EVM, Ewasm }; AssemblyStack(): - AssemblyStack(langutil::EVMVersion{}, Language::Assembly, solidity::frontend::OptimiserSettings::none()) + AssemblyStack( + langutil::EVMVersion{}, + Language::Assembly, + solidity::frontend::OptimiserSettings::none(), + langutil::DebugInfoSelection::Default() + ) {} - AssemblyStack(langutil::EVMVersion _evmVersion, Language _language, solidity::frontend::OptimiserSettings _optimiserSettings): + + AssemblyStack( + langutil::EVMVersion _evmVersion, + Language _language, + solidity::frontend::OptimiserSettings _optimiserSettings, + langutil::DebugInfoSelection const& _debugInfoSelection + ): m_language(_language), m_evmVersion(_evmVersion), m_optimiserSettings(std::move(_optimiserSettings)), + m_debugInfoSelection(_debugInfoSelection), m_errorReporter(m_errors) {} @@ -116,7 +129,9 @@ public: langutil::ErrorList const& errors() const { return m_errors; } /// Pretty-print the input after having parsed it. - std::string print(langutil::CharStreamProvider const* _soliditySourceProvider = nullptr) const; + std::string print( + langutil::CharStreamProvider const* _soliditySourceProvider = nullptr + ) const; /// Return the parsed and analyzed object. std::shared_ptr parserResult() const; @@ -132,6 +147,7 @@ private: Language m_language = Language::Assembly; langutil::EVMVersion m_evmVersion; solidity::frontend::OptimiserSettings m_optimiserSettings; + langutil::DebugInfoSelection m_debugInfoSelection{}; std::unique_ptr m_charStream; diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 2cc5578e8..30b97b5f7 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -34,6 +34,9 @@ add_library(yul AssemblyStack.cpp CompilabilityChecker.cpp CompilabilityChecker.h + ControlFlowSideEffects.h + ControlFlowSideEffectsCollector.cpp + ControlFlowSideEffectsCollector.h Dialect.cpp Dialect.h Exceptions.h @@ -216,4 +219,4 @@ add_library(yul optimiser/VarNameCleaner.h ) -target_link_libraries(yul PUBLIC evmasm solutil langutil smtutil) +target_link_libraries(yul PUBLIC evmasm solutil langutil smtutil fmt::fmt-header-only) diff --git a/libyul/ControlFlowSideEffects.h b/libyul/ControlFlowSideEffects.h index 5e22ad862..d4debab93 100644 --- a/libyul/ControlFlowSideEffects.h +++ b/libyul/ControlFlowSideEffects.h @@ -18,22 +18,32 @@ #pragma once -#include - namespace solidity::yul { /** - * Side effects of code related to control flow. + * Side effects of a user-defined or builtin function. + * + * Each of the three booleans represents a reachability condition. There is an implied + * fourth alternative, which is going out of gas while executing the function. Since + * this can always happen and depends on the supply of gas, it is not considered. + * + * If all three booleans are false, it means that the function always leads to infinite + * recursion. */ struct ControlFlowSideEffects { - /// If true, this code terminates the control flow. - /// State may or may not be reverted as indicated by the ``reverts`` flag. - bool terminates = false; - /// If true, this code reverts all state changes in the transaction. - /// Whenever this is true, ``terminates`` has to be true as well. - bool reverts = false; + /// If true, the function contains at least one reachable branch that terminates successfully. + bool canTerminate = false; + /// If true, the function contains at least one reachable branch that reverts. + bool canRevert = false; + /// If true, the function has a regular outgoing control-flow. + bool canContinue = true; + + bool terminatesOrReverts() const + { + return (canTerminate || canRevert) && !canContinue; + } }; } diff --git a/libyul/ControlFlowSideEffectsCollector.cpp b/libyul/ControlFlowSideEffectsCollector.cpp new file mode 100644 index 000000000..047480f14 --- /dev/null +++ b/libyul/ControlFlowSideEffectsCollector.cpp @@ -0,0 +1,274 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace solidity::yul; + + +ControlFlowBuilder::ControlFlowBuilder(Block const& _ast) +{ + for (auto const& statement: _ast.statements) + if (auto const* function = get_if(&statement)) + (*this)(*function); +} + +void ControlFlowBuilder::operator()(FunctionCall const& _functionCall) +{ + walkVector(_functionCall.arguments | ranges::views::reverse); + newConnectedNode(); + m_currentNode->functionCall = _functionCall.functionName.name; +} + +void ControlFlowBuilder::operator()(If const& _if) +{ + visit(*_if.condition); + ControlFlowNode* node = m_currentNode; + (*this)(_if.body); + newConnectedNode(); + node->successors.emplace_back(m_currentNode); +} + +void ControlFlowBuilder::operator()(Switch const& _switch) +{ + visit(*_switch.expression); + ControlFlowNode* initialNode = m_currentNode; + ControlFlowNode* finalNode = newNode(); + + if (_switch.cases.back().value) + initialNode->successors.emplace_back(finalNode); + + for (Case const& case_: _switch.cases) + { + m_currentNode = initialNode; + (*this)(case_.body); + newConnectedNode(); + m_currentNode->successors.emplace_back(finalNode); + } + m_currentNode = finalNode; +} + +void ControlFlowBuilder::operator()(FunctionDefinition const& _function) +{ + ScopedSaveAndRestore currentNode(m_currentNode, nullptr); + yulAssert(!m_leave && !m_break && !m_continue, "Function hoister has not been used."); + + FunctionFlow flow; + flow.exit = newNode(); + m_currentNode = newNode(); + flow.entry = m_currentNode; + m_leave = flow.exit; + + (*this)(_function.body); + + m_currentNode->successors.emplace_back(flow.exit); + + m_functionFlows[_function.name] = move(flow); + + m_leave = nullptr; +} + +void ControlFlowBuilder::operator()(ForLoop const& _for) +{ + ScopedSaveAndRestore scopedBreakNode(m_break, nullptr); + ScopedSaveAndRestore scopedContinueNode(m_continue, nullptr); + + (*this)(_for.pre); + + ControlFlowNode* breakNode = newNode(); + m_break = breakNode; + ControlFlowNode* continueNode = newNode(); + m_continue = continueNode; + + newConnectedNode(); + ControlFlowNode* loopNode = m_currentNode; + visit(*_for.condition); + m_currentNode->successors.emplace_back(m_break); + newConnectedNode(); + + (*this)(_for.body); + + m_currentNode->successors.emplace_back(m_continue); + m_currentNode = continueNode; + + (*this)(_for.post); + m_currentNode->successors.emplace_back(loopNode); + + m_currentNode = breakNode; +} + +void ControlFlowBuilder::operator()(Break const&) +{ + yulAssert(m_break); + m_currentNode->successors.emplace_back(m_break); + m_currentNode = newNode(); +} + +void ControlFlowBuilder::operator()(Continue const&) +{ + yulAssert(m_continue); + m_currentNode->successors.emplace_back(m_continue); + m_currentNode = newNode(); +} + +void ControlFlowBuilder::operator()(Leave const&) +{ + yulAssert(m_leave); + m_currentNode->successors.emplace_back(m_leave); + m_currentNode = newNode(); +} + +void ControlFlowBuilder::newConnectedNode() +{ + ControlFlowNode* node = newNode(); + m_currentNode->successors.emplace_back(node); + m_currentNode = node; +} + +ControlFlowNode* ControlFlowBuilder::newNode() +{ + m_nodes.emplace_back(make_shared()); + return m_nodes.back().get(); +} + + +ControlFlowSideEffectsCollector::ControlFlowSideEffectsCollector( + Dialect const& _dialect, + Block const& _ast +): + m_dialect(_dialect), + m_cfgBuilder(_ast) +{ + for (auto&& [name, flow]: m_cfgBuilder.functionFlows()) + { + yulAssert(!flow.entry->functionCall); + m_processedNodes[name] = {}; + m_pendingNodes[name].push_front(flow.entry); + m_functionSideEffects[name] = {false, false, false}; + } + + // Process functions while we have progress. For now, we are only interested + // in `canContinue`. + bool progress = true; + while (progress) + { + progress = false; + for (auto const& functionName: m_pendingNodes | ranges::views::keys) + if (processFunction(functionName)) + progress = true; + } + + // No progress anymore: All remaining nodes are calls + // to functions that always recurse. + // If we have not set `canContinue` by now, the function's exit + // is not reachable. + + for (auto&& [functionName, calls]: m_functionCalls) + { + ControlFlowSideEffects& sideEffects = m_functionSideEffects[functionName]; + auto _visit = [&, visited = std::set{}](YulString _function, auto&& _recurse) mutable { + if (sideEffects.canTerminate && sideEffects.canRevert) + return; + if (!visited.insert(_function).second) + return; + + ControlFlowSideEffects const* calledSideEffects = nullptr; + if (BuiltinFunction const* f = _dialect.builtin(_function)) + calledSideEffects = &f->controlFlowSideEffects; + else + calledSideEffects = &m_functionSideEffects.at(_function); + + if (calledSideEffects->canTerminate) + sideEffects.canTerminate = true; + if (calledSideEffects->canRevert) + sideEffects.canRevert = true; + + for (YulString callee: util::valueOrDefault(m_functionCalls, _function)) + _recurse(callee, _recurse); + }; + for (auto const& call: calls) + _visit(call, _visit); + } + +} + +bool ControlFlowSideEffectsCollector::processFunction(YulString _name) +{ + bool progress = false; + while (ControlFlowNode const* node = nextProcessableNode(_name)) + { + if (node == m_cfgBuilder.functionFlows().at(_name).exit) + { + m_functionSideEffects[_name].canContinue = true; + return true; + } + for (ControlFlowNode const* s: node->successors) + recordReachabilityAndQueue(_name, s); + + progress = true; + } + return progress; +} + +ControlFlowNode const* ControlFlowSideEffectsCollector::nextProcessableNode(YulString _functionName) +{ + std::list& nodes = m_pendingNodes[_functionName]; + auto it = ranges::find_if(nodes, [this](ControlFlowNode const* _node) { + return !_node->functionCall || sideEffects(*_node->functionCall).canContinue; + }); + if (it == nodes.end()) + return nullptr; + + ControlFlowNode const* node = *it; + nodes.erase(it); + return node; +} + +ControlFlowSideEffects const& ControlFlowSideEffectsCollector::sideEffects(YulString _functionName) const +{ + if (auto const* builtin = m_dialect.builtin(_functionName)) + return builtin->controlFlowSideEffects; + else + return m_functionSideEffects.at(_functionName); +} + +void ControlFlowSideEffectsCollector::recordReachabilityAndQueue( + YulString _functionName, + ControlFlowNode const* _node +) +{ + if (_node->functionCall) + m_functionCalls[_functionName].insert(*_node->functionCall); + if (m_processedNodes[_functionName].insert(_node).second) + m_pendingNodes.at(_functionName).push_front(_node); +} + diff --git a/libyul/ControlFlowSideEffectsCollector.h b/libyul/ControlFlowSideEffectsCollector.h new file mode 100644 index 000000000..f130294ba --- /dev/null +++ b/libyul/ControlFlowSideEffectsCollector.h @@ -0,0 +1,130 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace solidity::yul +{ + +struct Dialect; + +struct ControlFlowNode +{ + std::vector successors; + /// Name of the called function if the node calls a function. + std::optional functionCall; +}; + +/** + * The control flow of a function with entry and exit nodes. + */ +struct FunctionFlow +{ + ControlFlowNode const* entry; + ControlFlowNode const* exit; +}; + +/** + * Requires: Disambiguator, Function Hoister. + */ +class ControlFlowBuilder: private ASTWalker +{ +public: + /// Computes the control-flows of all function defined in the block. + /// Assumes the functions are hoisted to the topmost block. + explicit ControlFlowBuilder(Block const& _ast); + std::map const& functionFlows() const { return m_functionFlows; } + +private: + using ASTWalker::operator(); + void operator()(FunctionCall const& _functionCall) override; + void operator()(If const& _if) override; + void operator()(Switch const& _switch) override; + void operator()(FunctionDefinition const& _functionDefinition) override; + void operator()(ForLoop const& _forLoop) override; + void operator()(Break const& _break) override; + void operator()(Continue const& _continue) override; + void operator()(Leave const& _leaveStatement) override; + + void newConnectedNode(); + ControlFlowNode* newNode(); + + std::vector> m_nodes; + + ControlFlowNode* m_currentNode = nullptr; + ControlFlowNode const* m_leave = nullptr; + ControlFlowNode const* m_break = nullptr; + ControlFlowNode const* m_continue = nullptr; + + std::map m_functionFlows; +}; + + +/** + * Requires: Disambiguator, Function Hoister. + */ +class ControlFlowSideEffectsCollector +{ +public: + explicit ControlFlowSideEffectsCollector( + Dialect const& _dialect, + Block const& _ast + ); + + std::map const& functionSideEffects() const + { + return m_functionSideEffects; + } +private: + + /// @returns false if nothing could be processed. + bool processFunction(YulString _name); + + /// @returns the next pending node of the function that is not + /// a function call to a function that might not continue. + /// De-queues the node or returns nullptr if no such node is found. + ControlFlowNode const* nextProcessableNode(YulString _functionName); + + /// @returns the side-effects of either a builtin call or a user defined function + /// call (as far as already computed). + ControlFlowSideEffects const& sideEffects(YulString _functionName) const; + + /// Queues the given node to be processed (if not already visited) + /// and if it is a function call, records that `_functionName` calls + /// `*_node->functionCall`. + void recordReachabilityAndQueue(YulString _functionName, ControlFlowNode const* _node); + + Dialect const& m_dialect; + ControlFlowBuilder m_cfgBuilder; + std::map m_functionSideEffects; + std::map> m_pendingNodes; + std::map> m_processedNodes; + /// `x` is in `m_functionCalls[y]` if a direct call to `x` is reachable inside `y` + std::map> m_functionCalls; +}; + + +} diff --git a/libyul/Dialect.h b/libyul/Dialect.h index 87deb04b9..e7a5e4827 100644 --- a/libyul/Dialect.h +++ b/libyul/Dialect.h @@ -22,8 +22,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/libyul/Object.cpp b/libyul/Object.cpp index eee016aa4..ed456ab53 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -51,13 +51,14 @@ string indent(std::string const& _input) } -string Data::toString(Dialect const*, CharStreamProvider const*) const +string Data::toString(Dialect const*, DebugInfoSelection const&, CharStreamProvider const*) const { return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; } string Object::toString( Dialect const* _dialect, + DebugInfoSelection const& _debugInfoSelection, CharStreamProvider const* _soliditySourceProvider ) const { @@ -74,10 +75,15 @@ string Object::toString( })) + "\n"; - string inner = "code " + AsmPrinter{_dialect, debugData->sourceNames, _soliditySourceProvider}(*code); + string inner = "code " + AsmPrinter( + _dialect, + debugData->sourceNames, + _debugInfoSelection, + _soliditySourceProvider + )(*code); for (auto const& obj: subObjects) - inner += "\n" + obj->toString(_dialect, _soliditySourceProvider); + inner += "\n" + obj->toString(_dialect, _debugInfoSelection, _soliditySourceProvider); return useSrcComment + "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; } diff --git a/libyul/Object.h b/libyul/Object.h index 1b08821ce..f3c4ee34a 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -25,6 +25,7 @@ #include #include +#include #include @@ -54,6 +55,7 @@ struct ObjectNode YulString name; virtual std::string toString( Dialect const* _dialect, + langutil::DebugInfoSelection const& _debugInfoSelection, langutil::CharStreamProvider const* _soliditySourceProvider ) const = 0; }; @@ -69,6 +71,7 @@ struct Data: public ObjectNode std::string toString( Dialect const* _dialect, + langutil::DebugInfoSelection const& _debugInfoSelection, langutil::CharStreamProvider const* _soliditySourceProvider ) const override; }; @@ -89,6 +92,7 @@ public: /// @returns a (parseable) string representation. std::string toString( Dialect const* _dialect, + langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(), langutil::CharStreamProvider const* _soliditySourceProvider = nullptr ) const; diff --git a/libyul/SideEffects.h b/libyul/SideEffects.h index 7433e40d2..b6df8df83 100644 --- a/libyul/SideEffects.h +++ b/libyul/SideEffects.h @@ -94,7 +94,7 @@ struct SideEffects cannotLoop && _other.cannotLoop, otherState + _other.otherState, storage + _other.storage, - memory + _other.memory + memory + _other.memory }; } diff --git a/libyul/YulString.h b/libyul/YulString.h index fc3dedfd4..5522e3484 100644 --- a/libyul/YulString.h +++ b/libyul/YulString.h @@ -21,6 +21,8 @@ #pragma once +#include + #include #include #include @@ -166,6 +168,26 @@ inline YulString operator "" _yulstring(char const* _string, std::size_t _size) } } + +namespace fmt +{ +template <> +struct formatter +{ + template + constexpr auto parse(ParseContext& _context) + { + return _context.begin(); + } + + template + auto format(solidity::yul::YulString _value, FormatContext& _context) + { + return format_to(_context.out(), "{}", _value.str()); + } +}; +} + namespace std { template<> struct hash diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.cpp b/libyul/backends/evm/ControlFlowGraphBuilder.cpp index fd5b4682d..7e57b8257 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.cpp +++ b/libyul/backends/evm/ControlFlowGraphBuilder.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -230,7 +229,7 @@ void ControlFlowGraphBuilder::operator()(ExpressionStatement const& _exprStmt) // not only for builtins. if (auto const* funCall = get_if(&_exprStmt.expression)) if (BuiltinFunction const* builtin = m_dialect.builtin(funCall->functionName.name)) - if (builtin->controlFlowSideEffects.terminates) + if (builtin->controlFlowSideEffects.terminatesOrReverts()) { m_currentBlock->exit = CFG::BasicBlock::Terminated{}; m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock)); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index c90784a03..0fefb24d0 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -57,8 +57,20 @@ pair createEVMFunction( f.parameters.resize(static_cast(info.args)); f.returns.resize(static_cast(info.ret)); f.sideEffects = EVMDialect::sideEffectsOfInstruction(_instruction); - f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction); - f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction); + if (evmasm::SemanticInformation::terminatesControlFlow(_instruction)) + { + f.controlFlowSideEffects.canContinue = false; + if (evmasm::SemanticInformation::reverts(_instruction)) + { + f.controlFlowSideEffects.canTerminate = false; + f.controlFlowSideEffects.canRevert = true; + } + else + { + f.controlFlowSideEffects.canTerminate = true; + f.controlFlowSideEffects.canRevert = false; + } + } f.isMSize = _instruction == evmasm::Instruction::MSIZE; f.literalArguments.clear(); f.instruction = _instruction; diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp index 106e636c8..ca57c59d2 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp @@ -484,7 +484,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) yulAssert(!_block.operations.empty(), ""); CFG::BuiltinCall const* builtinCall = get_if(&_block.operations.back().operation); yulAssert(builtinCall, ""); - yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminates, ""); + yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminatesOrReverts(), ""); } }, _block.exit); // TODO: We could assert that the last emitted assembly item terminated or was an (unconditional) jump. diff --git a/libyul/backends/wasm/WasmDialect.cpp b/libyul/backends/wasm/WasmDialect.cpp index faaf366c1..817d53467 100644 --- a/libyul/backends/wasm/WasmDialect.cpp +++ b/libyul/backends/wasm/WasmDialect.cpp @@ -129,8 +129,9 @@ WasmDialect::WasmDialect() m_functions["unreachable"_yulstring].sideEffects.storage = SideEffects::None; m_functions["unreachable"_yulstring].sideEffects.memory = SideEffects::None; m_functions["unreachable"_yulstring].sideEffects.otherState = SideEffects::None; - m_functions["unreachable"_yulstring].controlFlowSideEffects.terminates = true; - m_functions["unreachable"_yulstring].controlFlowSideEffects.reverts = true; + m_functions["unreachable"_yulstring].controlFlowSideEffects.canTerminate = false; + m_functions["unreachable"_yulstring].controlFlowSideEffects.canRevert = true; + m_functions["unreachable"_yulstring].controlFlowSideEffects.canContinue = false; addFunction("datasize", {i64}, {i64}, true, {LiteralKind::String}); addFunction("dataoffset", {i64}, {i64}, true, {LiteralKind::String}); @@ -215,11 +216,11 @@ void WasmDialect::addExternals() {"eth", "log", {i32ptr, i32, i32, i32ptr, i32ptr, i32ptr, i32ptr}, {}}, {"eth", "getBlockNumber", {}, {i64}}, {"eth", "getTxOrigin", {i32ptr}, {}}, - {"eth", "finish", {i32ptr, i32}, {}, ControlFlowSideEffects{true, false}}, - {"eth", "revert", {i32ptr, i32}, {}, ControlFlowSideEffects{true, true}}, + {"eth", "finish", {i32ptr, i32}, {}, ControlFlowSideEffects{true, false, false}}, + {"eth", "revert", {i32ptr, i32}, {}, ControlFlowSideEffects{false, true, false}}, {"eth", "getReturnDataSize", {}, {i32}}, {"eth", "returnDataCopy", {i32ptr, i32, i32}, {}}, - {"eth", "selfDestruct", {i32ptr}, {}, ControlFlowSideEffects{true, false}}, + {"eth", "selfDestruct", {i32ptr}, {}, ControlFlowSideEffects{false, true, false}}, {"eth", "getBlockTimestamp", {}, {i64}}, {"debug", "print32", {i32}, {}}, {"debug", "print64", {i64}, {}}, @@ -240,7 +241,7 @@ void WasmDialect::addExternals() // TODO some of them are side effect free. f.sideEffects = SideEffects::worst(); f.sideEffects.cannotLoop = true; - f.sideEffects.movableApartFromEffects = !ext.controlFlowSideEffects.terminates; + f.sideEffects.movableApartFromEffects = !ext.controlFlowSideEffects.terminatesOrReverts(); f.controlFlowSideEffects = ext.controlFlowSideEffects; f.isMSize = false; f.literalArguments.clear(); diff --git a/libyul/optimiser/FunctionDefinitionCollector.cpp b/libyul/optimiser/FunctionDefinitionCollector.cpp index 70f2a268d..dff57a32a 100644 --- a/libyul/optimiser/FunctionDefinitionCollector.cpp +++ b/libyul/optimiser/FunctionDefinitionCollector.cpp @@ -22,7 +22,7 @@ using namespace std; using namespace solidity; using namespace solidity::yul; -map FunctionDefinitionCollector::run(Block& _block) +map FunctionDefinitionCollector::run(Block const& _block) { FunctionDefinitionCollector functionDefinitionCollector; functionDefinitionCollector(_block); diff --git a/libyul/optimiser/FunctionDefinitionCollector.h b/libyul/optimiser/FunctionDefinitionCollector.h index c97f20d67..c9828aced 100644 --- a/libyul/optimiser/FunctionDefinitionCollector.h +++ b/libyul/optimiser/FunctionDefinitionCollector.h @@ -34,7 +34,7 @@ namespace solidity::yul class FunctionDefinitionCollector: ASTWalker { public: - static std::map run(Block& _block); + static std::map run(Block const& _block); private: using ASTWalker::operator(); void operator()(FunctionDefinition const& _functionDefinition) override; diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 480a542a3..5525e17d2 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -78,6 +78,9 @@ #include #include +#include +#include + using namespace std; using namespace solidity; using namespace solidity::yul; @@ -87,7 +90,7 @@ void OptimiserSuite::run( GasMeter const* _meter, Object& _object, bool _optimizeStackAllocation, - string const& _optimisationSequence, + string_view _optimisationSequence, optional _expectedExecutionsPerDeployment, set const& _externallyUsedIdentifiers ) @@ -267,9 +270,9 @@ map const& OptimiserSuite::stepAbbreviationToNameMap() return lookupTable; } -void OptimiserSuite::validateSequence(string const& _stepAbbreviations) +void OptimiserSuite::validateSequence(string_view _stepAbbreviations) { - bool insideLoop = false; + int8_t nestingLevel = 0; for (char abbreviation: _stepAbbreviations) switch (abbreviation) { @@ -277,12 +280,12 @@ void OptimiserSuite::validateSequence(string const& _stepAbbreviations) case '\n': break; case '[': - assertThrow(!insideLoop, OptimizerException, "Nested brackets are not supported"); - insideLoop = true; + assertThrow(nestingLevel < numeric_limits::max(), OptimizerException, "Brackets nested too deep"); + nestingLevel++; break; case ']': - assertThrow(insideLoop, OptimizerException, "Unbalanced brackets"); - insideLoop = false; + nestingLevel--; + assertThrow(nestingLevel >= 0, OptimizerException, "Unbalanced brackets"); break; default: { @@ -301,43 +304,99 @@ void OptimiserSuite::validateSequence(string const& _stepAbbreviations) OptimizerException, "'"s + abbreviation + "' is invalid in the current environment: " + *invalid ); - } } - assertThrow(!insideLoop, OptimizerException, "Unbalanced brackets"); + assertThrow(nestingLevel == 0, OptimizerException, "Unbalanced brackets"); } -void OptimiserSuite::runSequence(string const& _stepAbbreviations, Block& _ast) +void OptimiserSuite::runSequence(string_view _stepAbbreviations, Block& _ast, bool _repeatUntilStable) { validateSequence(_stepAbbreviations); - string input = _stepAbbreviations; - ranges::actions::remove(input, ' '); - ranges::actions::remove(input, '\n'); + // This splits 'aaa[bbb]ccc...' into 'aaa' and '[bbb]ccc...'. + auto extractNonNestedPrefix = [](string_view _tail) -> tuple + { + for (size_t i = 0; i < _tail.size(); ++i) + { + yulAssert(_tail[i] != ']'); + if (_tail[i] == '[') + return {_tail.substr(0, i), _tail.substr(i)}; + } + return {_tail, {}}; + }; - auto abbreviationsToSteps = [](string const& _sequence) -> vector + // This splits '[bbb]ccc...' into 'bbb' and 'ccc...'. + auto extractBracketContent = [](string_view _tail) -> tuple + { + yulAssert(!_tail.empty() && _tail[0] == '['); + + size_t contentLength = 0; + int8_t nestingLevel = 1; + for (char abbreviation: _tail.substr(1)) + { + if (abbreviation == '[') + { + yulAssert(nestingLevel < numeric_limits::max()); + ++nestingLevel; + } + else if (abbreviation == ']') + { + --nestingLevel; + if (nestingLevel == 0) + break; + } + ++contentLength; + } + yulAssert(nestingLevel == 0); + yulAssert(_tail[contentLength + 1] == ']'); + + return {_tail.substr(1, contentLength), _tail.substr(contentLength + 2)}; + }; + + auto abbreviationsToSteps = [](string_view _sequence) -> vector { vector steps; for (char abbreviation: _sequence) - steps.emplace_back(stepAbbreviationToNameMap().at(abbreviation)); + if (abbreviation != ' ' && abbreviation != '\n') + steps.emplace_back(stepAbbreviationToNameMap().at(abbreviation)); return steps; }; - // The sequence has now been validated and must consist of pairs of segments that look like this: `aaa[bbb]` - // `aaa` or `[bbb]` can be empty. For example we consider a sequence like `fgo[aaf]Oo` to have - // four segments, the last of which is an empty bracket. - size_t currentPairStart = 0; - while (currentPairStart < input.size()) + vector> subsequences; + string_view tail = _stepAbbreviations; + while (!tail.empty()) { - size_t openingBracket = input.find('[', currentPairStart); - size_t closingBracket = input.find(']', openingBracket); - size_t firstCharInside = (openingBracket == string::npos ? input.size() : openingBracket + 1); - yulAssert((openingBracket == string::npos) == (closingBracket == string::npos), ""); + string_view subsequence; + tie(subsequence, tail) = extractNonNestedPrefix(tail); + if (subsequence.size() > 0) + subsequences.push_back({subsequence, false}); - runSequence(abbreviationsToSteps(input.substr(currentPairStart, openingBracket - currentPairStart)), _ast); - runSequenceUntilStable(abbreviationsToSteps(input.substr(firstCharInside, closingBracket - firstCharInside)), _ast); + if (tail.empty()) + break; - currentPairStart = (closingBracket == string::npos ? input.size() : closingBracket + 1); + tie(subsequence, tail) = extractBracketContent(tail); + if (subsequence.size() > 0) + subsequences.push_back({subsequence, true}); + } + + size_t codeSize = 0; + for (size_t round = 0; round < MaxRounds; ++round) + { + for (auto const& [subsequence, repeat]: subsequences) + { + if (repeat) + runSequence(subsequence, _ast, true); + else + runSequence(abbreviationsToSteps(subsequence), _ast); + } + + if (!_repeatUntilStable) + break; + + size_t newSize = CodeSize::codeSizeIncludingFunctions(_ast); + if (newSize == codeSize) + break; + codeSize = newSize; } } @@ -365,24 +424,3 @@ void OptimiserSuite::runSequence(std::vector const& _steps, Block& _ast) } } } - -void OptimiserSuite::runSequenceUntilStable( - std::vector const& _steps, - Block& _ast, - size_t maxRounds -) -{ - if (_steps.empty()) - return; - - size_t codeSize = 0; - for (size_t rounds = 0; rounds < maxRounds; ++rounds) - { - size_t newSize = CodeSize::codeSizeIncludingFunctions(_ast); - if (newSize == codeSize) - break; - codeSize = newSize; - - runSequence(_steps, _ast); - } -} diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index fa7b06bd0..9b38ce542 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -29,6 +29,7 @@ #include #include +#include #include namespace solidity::yul @@ -64,22 +65,17 @@ public: GasMeter const* _meter, Object& _object, bool _optimizeStackAllocation, - std::string const& _optimisationSequence, + std::string_view _optimisationSequence, std::optional _expectedExecutionsPerDeployment, std::set const& _externallyUsedIdentifiers = {} ); /// Ensures that specified sequence of step abbreviations is well-formed and can be executed. /// @throw OptimizerException if the sequence is invalid - static void validateSequence(std::string const& _stepAbbreviations); + static void validateSequence(std::string_view _stepAbbreviations); void runSequence(std::vector const& _steps, Block& _ast); - void runSequence(std::string const& _stepAbbreviations, Block& _ast); - void runSequenceUntilStable( - std::vector const& _steps, - Block& _ast, - size_t maxRounds = MaxRounds - ); + void runSequence(std::string_view _stepAbbreviations, Block& _ast, bool _repeatUntilStable = false); static std::map> const& allSteps(); static std::map const& stepNameToAbbreviationMap(); diff --git a/scripts/bytecodecompare/prepare_report.py b/scripts/bytecodecompare/prepare_report.py index 33463f198..9d35b9988 100755 --- a/scripts/bytecodecompare/prepare_report.py +++ b/scripts/bytecodecompare/prepare_report.py @@ -413,7 +413,7 @@ def commandline_parser() -> ArgumentParser: action='store_true', help="Immediately exit and print compiler output if the compiler exits with an error.", ) - return parser; + return parser if __name__ == "__main__": diff --git a/scripts/common_cmdline.sh b/scripts/common_cmdline.sh index 6718ca5b5..15d93f562 100644 --- a/scripts/common_cmdline.sh +++ b/scripts/common_cmdline.sh @@ -20,7 +20,7 @@ # ------------------------------------------------------------------------------ YULARGS=(--strict-assembly) -FULLARGS=(--optimize --ignore-missing --combined-json "abi,asm,ast,bin,bin-runtime,devdoc,hashes,metadata,opcodes,srcmap,srcmap-runtime,userdoc") +FULLARGS=(--optimize --combined-json "abi,asm,ast,bin,bin-runtime,devdoc,hashes,metadata,opcodes,srcmap,srcmap-runtime,userdoc") OLDARGS=(--optimize --combined-json "abi,asm,ast,bin,bin-runtime,devdoc,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc") function compileFull() { @@ -99,7 +99,7 @@ function compileFull() printError "Inside directory:" echo " $(pwd)" printError "Input was:" - cat -- "${files[@]}" + echo "${files[@]}" false fi } diff --git a/scripts/endToEndExtraction/remove-testcases.py b/scripts/endToEndExtraction/remove-testcases.py index b1dc75b6c..28822e044 100755 --- a/scripts/endToEndExtraction/remove-testcases.py +++ b/scripts/endToEndExtraction/remove-testcases.py @@ -39,7 +39,7 @@ def colorize(left, right, id): reset = "\x1b[0m" colors = [red, yellow] color = colors[id % len(colors)] - function, arguments, results = parse_call(right) + function, _arguments, _results = parse_call(right) left = left.replace("compileAndRun", color + "compileAndRun" + reset) right = right.replace("constructor", color + "constructor" + reset) if function: @@ -158,7 +158,7 @@ def main(argv): interactive = False input_file = None try: - opts, args = getopt.getopt(argv, "if:") + opts, _args = getopt.getopt(argv, "if:") except getopt.GetoptError: print("./remove-testcases.py [-i] [-f ]") sys.exit(1) diff --git a/scripts/endToEndExtraction/verify-testcases.py b/scripts/endToEndExtraction/verify-testcases.py index c86a993dc..8e1c60a79 100755 --- a/scripts/endToEndExtraction/verify-testcases.py +++ b/scripts/endToEndExtraction/verify-testcases.py @@ -158,7 +158,7 @@ class TraceAnalyser: for trace_id, trace in enumerate(left.traces): left_trace = trace right_trace = right.traces[trace_id] - assert (left_trace.kind == right_trace.kind) + assert left_trace.kind == right_trace.kind if str(left_trace) != str(right_trace): mismatch_info = " " + str(left_trace) + "\n" mismatch_info += " " + str(right_trace) + "\n" @@ -179,7 +179,7 @@ def main(argv): extracted_tests_trace_file = None end_to_end_trace_file = None try: - opts, args = getopt.getopt(argv, "s:e:") + opts, _args = getopt.getopt(argv, "s:e:") except getopt.GetoptError: print("verify-testcases.py [-s ] [-e ]") sys.exit(2) diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 8d919e41b..9290211a2 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -261,9 +261,9 @@ def main(argv): no_confirm = False examine_coverage = False next_id = False - opts, args = getopt.getopt(argv, "", ["check", "fix", "no-confirm", "examine-coverage", "next"]) + opts, _args = getopt.getopt(argv, "", ["check", "fix", "no-confirm", "examine-coverage", "next"]) - for opt, arg in opts: + for opt, _arg in opts: if opt == "--check": check = True elif opt == "--fix": diff --git a/scripts/fix_homebrew_paths_in_standalone_zip.py b/scripts/fix_homebrew_paths_in_standalone_zip.py index 95120f760..43f26795c 100755 --- a/scripts/fix_homebrew_paths_in_standalone_zip.py +++ b/scripts/fix_homebrew_paths_in_standalone_zip.py @@ -49,9 +49,10 @@ def readDependencies(fname): if line[0] == '\t': library = line.split(' ', 1)[0][1:] if (library.startswith("/usr/local/lib") or - library.startswith("/usr/local/opt") or - library.startswith("/Users/")): - if (os.path.basename(library) != os.path.basename(fname)): + library.startswith("/usr/local/opt") or + library.startswith("/Users/") + ): + if os.path.basename(library) != os.path.basename(fname): command = "install_name_tool -change " + \ library + " @executable_path/./" + \ os.path.basename(library) + " " + fname diff --git a/scripts/gas_diff_stats.py b/scripts/gas_diff_stats.py index 1e86e2836..5c7aa5338 100644 --- a/scripts/gas_diff_stats.py +++ b/scripts/gas_diff_stats.py @@ -20,7 +20,7 @@ repository. The changes are compared against ``origin/develop``. import subprocess from pathlib import Path from enum import Enum -from parsec import * +from parsec import generate, ParseError, regex, string from tabulate import tabulate class Kind(Enum): @@ -56,10 +56,10 @@ def diff_string() -> (Kind, Diff, int): -// gas irOptimized: 138070 """ - diff_kind = yield (minus | plus) + diff_kind = yield minus | plus yield comment yield space - codegen_kind = yield (gas_ir_optimized ^ gas_legacy_optimized ^ gas_legacy) + codegen_kind = yield gas_ir_optimized ^ gas_legacy_optimized ^ gas_legacy yield colon yield space val = yield number() diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index ddea2e8b7..6a9c12f3f 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -179,16 +179,6 @@ case $(uname -s) in . /etc/os-release install_z3="" case $VERSION_ID in - 7) - #wheezy - echo "Installing solidity dependencies on Debian Wheezy (7.x)." - echo "ERROR - 'install_deps.sh' doesn't have Debian Wheezy support yet." - echo "See https://docs.soliditylang.org/en/latest/installing-solidity.html for manual instructions." - echo "If you would like to get 'install_deps.sh' working for Debian Wheezy, that would be fantastic." - echo "Drop us a message at https://gitter.im/ethereum/solidity-dev." - echo "See also https://github.com/ethereum/webthree-umbrella/issues/495 where we are working through Alpine support." - exit 1 - ;; 8) #jessie echo "Installing solidity dependencies on Debian Jesse (8.x)." @@ -277,32 +267,11 @@ case $(uname -s) in echo "Installing solidity dependencies on Ubuntu Trusty Tahr (14.04)." echo "Or, you may also be running Linux Mint Qiana / Rebecca / Rafaela / Rosa (base: Ubuntu Trusty Tahr (14.04).)" ;; - utopic) - echo "Installing solidity dependencies on Ubuntu Utopic Unicorn (14.10)." - ;; - vivid) - echo "Installing solidity dependencies on Ubuntu Vivid Vervet (15.04)." - ;; - wily) - echo "Installing solidity dependencies on Ubuntu Wily Werewolf (15.10)." - ;; xenial|sarah|serena|sonya|sylvia) echo "Installing solidity dependencies on Ubuntu Xenial Xerus (16.04)." echo "Or, you may also be running Linux Mint Sarah / Serena / Sonya / Sylvia (base: Ubuntu Xenial Xerus (16.04).)" install_z3="libz3-dev" ;; - yakkety) - echo "Installing solidity dependencies on Ubuntu Yakkety Yak (16.10)." - install_z3="libz3-dev" - ;; - zesty) - echo "Installing solidity dependencies on Ubuntu Zesty (17.04)." - install_z3="libz3-dev" - ;; - artful) - echo "Installing solidity dependencies on Ubuntu Artful (17.10)." - install_z3="libz3-dev" - ;; bionic) echo "Installing solidity dependencies." install_z3="libz3-dev" @@ -311,6 +280,10 @@ case $(uname -s) in echo "Installing solidity dependencies." install_z3="libz3-dev" ;; + hirsute) + echo "Installing solidity dependencies." + install_z3="libz3-dev" + ;; betsy) #do not try anything for betsy. echo "Linux Mint Betsy is not supported at the moment as it runs off of Debian." @@ -325,7 +298,7 @@ case $(uname -s) in echo "ERROR - Unknown or unsupported Ubuntu version ($(lsb_release -cs))" echo "ERROR - This might not work, but we are trying anyway." echo "Please drop us a message at https://gitter.im/ethereum/solidity-dev." - echo "We only support Trusty, Utopic, Vivid, Wily, Xenial, Yakkety, Zesty, Artful and Bionic." + echo "We only support Trusty, Xenial, Bionic, Focal, and Hirsute." install_z3="libz3-dev" ;; esac diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py index 93cf2755c..1e2170e82 100755 --- a/scripts/isolate_tests.py +++ b/scripts/isolate_tests.py @@ -6,7 +6,6 @@ # into files for e.g. fuzz testing as # scripts/isolate_tests.py test/libsolidity/* -import sys import re import os import hashlib diff --git a/scripts/pylint_all.py b/scripts/pylint_all.py index 7b8924b8a..8dbe6a7fc 100755 --- a/scripts/pylint_all.py +++ b/scripts/pylint_all.py @@ -9,7 +9,6 @@ from os import path, walk from sys import exit from textwrap import dedent import subprocess -import sys PROJECT_ROOT = path.dirname(path.dirname(path.realpath(__file__))) PYLINT_RCFILE = f"{PROJECT_ROOT}/scripts/pylintrc" diff --git a/scripts/pylintrc b/scripts/pylintrc index ed63c9256..50dbebee0 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -24,24 +24,15 @@ disable= duplicate-code, invalid-name, missing-docstring, - mixed-indentation, no-else-return, no-self-use, pointless-string-statement, redefined-builtin, redefined-outer-name, singleton-comparison, - superfluous-parens, too-few-public-methods, - trailing-newlines, - undefined-variable, - ungrouped-imports, - unnecessary-semicolon, - unused-import, - unused-variable, - unused-wildcard-import, - useless-object-inheritance, - wildcard-import + too-many-public-methods, + ungrouped-imports [BASIC] diff --git a/scripts/regressions.py b/scripts/regressions.py index 1efbb48b5..046044197 100755 --- a/scripts/regressions.py +++ b/scripts/regressions.py @@ -11,7 +11,7 @@ import time DESCRIPTION = """Regressor is a tool to run regression tests in a CI env.""" -class PrintDotsThread(object): +class PrintDotsThread: """Prints a dot every "interval" (default is 300) seconds""" def __init__(self, interval=300): @@ -30,7 +30,7 @@ class PrintDotsThread(object): print(".") time.sleep(self.interval) -class regressor(): +class regressor: _re_sanitizer_log = re.compile(r"""ERROR: (libFuzzer|UndefinedBehaviorSanitizer)""") def __init__(self, description, args): diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index a798b96a5..60e931083 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -105,10 +105,11 @@ ppafilesurl=https://launchpad.net/~ethereum/+archive/ubuntu/${pparepo}/+files git clone --depth 2 --recursive https://github.com/ethereum/solidity.git -b "$branch" mv solidity solc -# Fetch jsoncpp dependency +# Fetch dependencies mkdir -p ./solc/deps/downloads/ 2>/dev/null || true wget -O ./solc/deps/downloads/jsoncpp-1.9.3.tar.gz https://github.com/open-source-parsers/jsoncpp/archive/1.9.3.tar.gz wget -O ./solc/deps/downloads/range-v3-0.11.0.tar.gz https://github.com/ericniebler/range-v3/archive/0.11.0.tar.gz +wget -O ./solc/deps/downloads/fmt-8.0.1.tar.gz https://github.com/fmtlib/fmt/archive/8.0.1.tar.gz # Determine version cd solc diff --git a/scripts/splitSources.py b/scripts/splitSources.py index 3d1c8ef45..181741f9c 100755 --- a/scripts/splitSources.py +++ b/scripts/splitSources.py @@ -44,9 +44,7 @@ def writeSourceToFile(lines): os.system("mkdir -p " + filePath) with open(srcName, mode='a+', encoding='utf8', newline='') as f: createdSources.append(srcName) - i = 0 for idx, line in enumerate(lines[1:]): - # write to file if line[:12] != "==== Source:": f.write(line) diff --git a/scripts/wasm-rebuild/docker-scripts/isolate_tests.py b/scripts/wasm-rebuild/docker-scripts/isolate_tests.py index 635ebcc31..c447c1e67 100755 --- a/scripts/wasm-rebuild/docker-scripts/isolate_tests.py +++ b/scripts/wasm-rebuild/docker-scripts/isolate_tests.py @@ -7,7 +7,8 @@ import sys import re import os import hashlib -from os.path import join, isfile +# Pylint for some reason insists that isfile() is unused +from os.path import join, isfile # pylint: disable=unused-import def extract_test_cases(path): diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 0826749ee..e462823e8 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -41,9 +41,9 @@ parts: source-tag: z3-4.8.4 plugin: make build-packages: [python3] - stage-packages: [libstdc++6] + stage-packages: [libstdc++6, libgomp1] override-build: | - python scripts/mk_make.py + python3 scripts/mk_make.py cd build make -j -l $(grep -c "^processor" /proc/cpuinfo) make install DESTDIR=$SNAPCRAFT_PART_INSTALL diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index dfe5cfc5c..6c24b7742 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -553,7 +553,7 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da if (fs::exists(pathName) && !m_options.output.overwriteFiles) { serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --overwrite to force)." << endl; - m_error = true; + m_outputFailed = true; return; } ofstream outFile(pathName); @@ -561,7 +561,7 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da if (!outFile) { serr() << "Could not write to file \"" << pathName << "\"." << endl; - m_error = true; + m_outputFailed = true; return; } } @@ -631,6 +631,8 @@ bool CommandLineInterface::compile() m_compiler->setViaIR(m_options.output.experimentalViaIR); m_compiler->setEVMVersion(m_options.output.evmVersion); m_compiler->setRevertStringBehaviour(m_options.output.revertStrings); + if (m_options.output.debugInfoSelection.has_value()) + m_compiler->selectDebugInfo(m_options.output.debugInfoSelection.value()); // TODO: Perhaps we should not compile unless requested m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized); @@ -699,30 +701,6 @@ bool CommandLineInterface::compile() formatter.printExceptionInformation(_exception, "Compiler error"); return false; } - catch (InternalCompilerError const& _exception) - { - serr() << - "Internal compiler error during compilation:" << - endl << - boost::diagnostic_information(_exception); - return false; - } - catch (UnimplementedFeatureError const& _exception) - { - serr() << - "Unimplemented feature:" << - endl << - boost::diagnostic_information(_exception); - return false; - } - catch (smtutil::SMTLogicError const& _exception) - { - serr() << - "SMT logic error during analysis:" << - endl << - boost::diagnostic_information(_exception); - return false; - } catch (Error const& _error) { if (_error.type() == Error::Type::DocstringParsingError) @@ -735,23 +713,6 @@ bool CommandLineInterface::compile() return false; } - catch (Exception const& _exception) - { - serr() << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl; - return false; - } - catch (std::exception const& _e) - { - serr() << "Unknown exception during compilation" << ( - _e.what() ? ": " + string(_e.what()) : "." - ) << endl; - return false; - } - catch (...) - { - serr() << "Unknown exception during compilation." << endl; - return false; - } return true; } @@ -894,7 +855,7 @@ bool CommandLineInterface::actOnInput() solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); outputCompilationResults(); } - return !m_error; + return !m_outputFailed; } bool CommandLineInterface::link() @@ -976,6 +937,7 @@ void CommandLineInterface::writeLinkedFiles() if (!outFile) { serr() << "Could not write to file " << src.first << ". Aborting." << endl; + m_outputFailed = true; return; } } @@ -1013,34 +975,16 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul: auto& stack = assemblyStacks[src.first] = yul::AssemblyStack( m_options.output.evmVersion, _language, - m_options.optimiserSettings() + m_options.optimiserSettings(), + m_options.output.debugInfoSelection.has_value() ? + m_options.output.debugInfoSelection.value() : + DebugInfoSelection::Default() ); - try - { - if (!stack.parseAndAnalyze(src.first, src.second)) - successful = false; - else - stack.optimize(); - } - catch (Exception const& _exception) - { - serr() << "Exception in assembler: " << boost::diagnostic_information(_exception) << endl; - return false; - } - catch (std::exception const& _e) - { - serr() << - "Unknown exception during compilation" << - (_e.what() ? ": " + string(_e.what()) : ".") << - endl; - return false; - } - catch (...) - { - serr() << "Unknown exception in assembler." << endl; - return false; - } + if (!stack.parseAndAnalyze(src.first, src.second)) + successful = false; + else + stack.optimize(); } for (auto const& sourceAndStack: assemblyStacks) @@ -1074,29 +1018,8 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul: if (_language != yul::AssemblyStack::Language::Ewasm && _targetMachine == yul::AssemblyStack::Machine::Ewasm) { - try - { - stack.translate(yul::AssemblyStack::Language::Ewasm); - stack.optimize(); - } - catch (Exception const& _exception) - { - serr() << "Exception in assembler: " << boost::diagnostic_information(_exception) << endl; - return false; - } - catch (std::exception const& _e) - { - serr() << - "Unknown exception during compilation" << - (_e.what() ? ": " + string(_e.what()) : ".") << - endl; - return false; - } - catch (...) - { - serr() << "Unknown exception in assembler." << endl; - return false; - } + stack.translate(yul::AssemblyStack::Language::Ewasm); + stack.optimize(); sout() << endl << "==========================" << endl; sout() << endl << "Translated source:" << endl; @@ -1104,28 +1027,8 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul: } yul::MachineAssemblyObject object; - try - { - object = stack.assemble(_targetMachine); - object.bytecode->link(m_options.linker.libraries); - } - catch (Exception const& _exception) - { - serr() << "Exception while assembling: " << boost::diagnostic_information(_exception) << endl; - return false; - } - catch (std::exception const& _e) - { - serr() << "Unknown exception during compilation" << ( - _e.what() ? ": " + string(_e.what()) : "." - ) << endl; - return false; - } - catch (...) - { - serr() << "Unknown exception while assembling." << endl; - return false; - } + object = stack.assemble(_targetMachine); + object.bytecode->link(m_options.linker.libraries); sout() << endl << "Binary representation:" << endl; if (object.bytecode) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 5504e51bb..1ca40568c 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -121,7 +121,7 @@ private: std::ostream& m_sout; std::ostream& m_serr; bool m_hasOutput = false; - bool m_error = false; ///< If true, some error occurred. + bool m_outputFailed = false; ///< If true, creation or write to some of the output files failed. FileReader m_fileReader; std::optional m_standardJsonInput; std::unique_ptr m_compiler; diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 26b8dd255..89304ef3c 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -67,6 +67,7 @@ static string const g_strImportAst = "import-ast"; static string const g_strInputFile = "input-file"; static string const g_strYul = "yul"; static string const g_strYulDialect = "yul-dialect"; +static string const g_strDebugInfo = "debug-info"; static string const g_strIPFS = "ipfs"; static string const g_strLicense = "license"; static string const g_strLibraries = "libraries"; @@ -137,6 +138,14 @@ static set const g_metadataHashArgs g_strNone }; +static map const g_inputModeName = { + {InputMode::Compiler, "compiler"}, + {InputMode::CompilerWithASTImport, "compiler (AST import)"}, + {InputMode::Assembler, "assembler"}, + {InputMode::StandardJson, "standard JSON"}, + {InputMode::Linker, "linker"}, +}; + void CommandLineParser::printVersionAndExit() { sout() << @@ -244,6 +253,7 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex output.evmVersion == _other.output.evmVersion && output.experimentalViaIR == _other.output.experimentalViaIR && output.revertStrings == _other.output.revertStrings && + output.debugInfoSelection == _other.output.debugInfoSelection && output.stopAfter == _other.output.stopAfter && input.mode == _other.input.mode && assembly.targetMachine == _other.assembly.targetMachine && @@ -460,6 +470,47 @@ bool CommandLineParser::parseLibraryOption(string const& _input) return true; } +bool CommandLineParser::parseOutputSelection() +{ + static auto outputSupported = [](InputMode _mode, string_view _outputName) + { + static set const compilerModeOutputs = + CompilerOutputs::componentMap() | + ranges::views::keys | + ranges::to(); + + switch (_mode) + { + case InputMode::Compiler: + case InputMode::CompilerWithASTImport: + return contains(compilerModeOutputs, _outputName); + case InputMode::Assembler: + case InputMode::StandardJson: + case InputMode::Linker: + return false; + } + + solAssert(false, ""); + }; + + for (auto&& [optionName, outputComponent]: CompilerOutputs::componentMap()) + m_options.compiler.outputs.*outputComponent = (m_args.count(optionName) > 0); + + vector unsupportedOutputs; + for (auto&& [optionName, outputComponent]: CompilerOutputs::componentMap()) + if (m_options.compiler.outputs.*outputComponent && !outputSupported(m_options.input.mode, optionName)) + unsupportedOutputs.push_back(optionName); + + if (!unsupportedOutputs.empty()) + { + serr() << "The following outputs are not supported in " << g_inputModeName.at(m_options.input.mode) << " mode: "; + serr() << joinOptionNames(unsupportedOutputs) << "."; + return false; + } + + return true; +} + po::options_description CommandLineParser::optionsDescription() { // Declare the supported options. @@ -546,6 +597,13 @@ General Information)").c_str(), po::value()->value_name(joinHumanReadable(g_revertStringsArgs, ",")), "Strip revert (and require) reason strings or add additional debugging information." ) + ( + g_strDebugInfo.c_str(), + po::value()->default_value(toString(DebugInfoSelection::Default())), + ("Debug info components to be included in the produced EVM assembly and Yul code. " + "Value can be all, none or a comma-separated list containing one or more of the " + "following components: " + joinHumanReadable(DebugInfoSelection::componentMap() | ranges::views::keys) + ".").c_str() + ) ( g_strStopAfter.c_str(), po::value()->value_name("stage"), @@ -886,6 +944,12 @@ bool CommandLineParser::processArgs() serr() << "Option --" << option << " is only valid in compiler and assembler modes." << endl; return false; } + + if (!m_args[g_strDebugInfo].defaulted()) + { + serr() << "Option --" << g_strDebugInfo << " is only valid in compiler and assembler modes." << endl; + return false; + } } if (m_args.count(g_strColor) > 0) @@ -912,6 +976,23 @@ bool CommandLineParser::processArgs() m_options.output.revertStrings = *revertStrings; } + if (!m_args[g_strDebugInfo].defaulted()) + { + string optionValue = m_args[g_strDebugInfo].as(); + m_options.output.debugInfoSelection = DebugInfoSelection::fromString(optionValue); + if (!m_options.output.debugInfoSelection.has_value()) + { + serr() << "Invalid value for --" << g_strDebugInfo << " option: " << optionValue << endl; + return false; + } + + if (m_options.output.debugInfoSelection->snippet && !m_options.output.debugInfoSelection->location) + { + serr() << "To use 'snippet' with --" << g_strDebugInfo << " you must select also 'location'." << endl; + return false; + } + } + if (!parseCombinedJsonOption()) return false; @@ -930,8 +1011,8 @@ bool CommandLineParser::processArgs() m_options.formatting.json.indent = m_args[g_strJsonIndent].as(); } - for (auto&& [optionName, outputComponent]: CompilerOutputs::componentMap()) - m_options.compiler.outputs.*outputComponent = (m_args.count(optionName) > 0); + if (!parseOutputSelection()) + return false; m_options.compiler.estimateGas = (m_args.count(g_strGas) > 0); diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 7e1266653..ad525ea3b 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -24,8 +24,12 @@ #include #include #include + #include + +#include #include + #include #include @@ -174,6 +178,7 @@ struct CommandLineOptions langutil::EVMVersion evmVersion; bool experimentalViaIR = false; RevertStrings revertStrings = RevertStrings::Default; + std::optional debugInfoSelection; CompilerStack::State stopAfter = CompilerStack::State::CompilationSuccessful; } output; @@ -286,6 +291,8 @@ private: /// @return false if there are any validation errors, true otherwise. bool parseLibraryOption(std::string const& _input); + bool parseOutputSelection(); + bool checkMutuallyExclusive(std::vector const& _optionNames); [[noreturn]] void printVersionAndExit(); [[noreturn]] void printLicenseAndExit(); diff --git a/solc/main.cpp b/solc/main.cpp index 9eefc1afd..1299e2564 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -22,11 +22,16 @@ */ #include + +#include + #include + #include #include using namespace std; +using namespace solidity; /* The equivalent of setlocale(LC_ALL, "C") is called before any user code is run. @@ -53,24 +58,52 @@ static void setDefaultOrCLocale() int main(int argc, char** argv) { - setDefaultOrCLocale(); - solidity::frontend::CommandLineInterface cli(cin, cout, cerr); - if (!cli.parseArguments(argc, argv)) - return 1; - if (!cli.readInputFiles()) - return 1; - if (!cli.processInput()) - return 1; - bool success = false; try { - success = cli.actOnInput(); + setDefaultOrCLocale(); + solidity::frontend::CommandLineInterface cli(cin, cout, cerr); + bool success = + cli.parseArguments(argc, argv) && + cli.readInputFiles() && + cli.processInput() && + cli.actOnInput(); + + return success ? 0 : 1; + } + catch (smtutil::SMTLogicError const& _exception) + { + cerr << "SMT logic error:" << endl; + cerr << boost::diagnostic_information(_exception); + return 1; + } + catch (langutil::UnimplementedFeatureError const& _exception) + { + cerr << "Unimplemented feature:" << endl; + cerr << boost::diagnostic_information(_exception); + return 1; + } + catch (langutil::InternalCompilerError const& _exception) + { + cerr << "Internal compiler error:" << endl; + cerr << boost::diagnostic_information(_exception); + return 1; } catch (boost::exception const& _exception) { - cerr << "Exception during output generation: " << boost::diagnostic_information(_exception) << endl; - success = false; + cerr << "Uncaught exception:" << endl; + cerr << boost::diagnostic_information(_exception) << endl; + return 1; + } + catch (std::exception const& _exception) + { + cerr << "Uncaught exception:" << endl; + cerr << boost::diagnostic_information(_exception) << endl; + return 1; + } + catch (...) + { + cerr << "Uncaught exception" << endl; + cerr << boost::current_exception_diagnostic_information() << endl; + return 1; } - - return success ? 0 : 1; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3135b53d5..3a0b5f7b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -130,6 +130,8 @@ set(libyul_sources libyul/CompilabilityChecker.cpp libyul/ControlFlowGraphTest.cpp libyul/ControlFlowGraphTest.h + libyul/ControlFlowSideEffectsTest.cpp + libyul/ControlFlowSideEffectsTest.h libyul/EVMCodeTransformTest.cpp libyul/EVMCodeTransformTest.h libyul/EwasmTranslationTest.cpp diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index e27c00b84..d8f3ef07e 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -57,12 +58,12 @@ struct Testsuite Testsuite const g_interactiveTestsuites[] = { /* Title Path Subpath SMT NeedsVM Creator function */ - {"Ewasm Translation", "libyul", "ewasmTranslationTests", false, false, &yul::test::EwasmTranslationTest::create}, {"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create}, {"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, {"Yul Control Flow Graph", "libyul", "yulControlFlowGraph", false, false, &yul::test::ControlFlowGraphTest::create}, {"Yul Stack Layout", "libyul", "yulStackLayout", false, false, &yul::test::StackLayoutGeneratorTest::create}, + {"Control Flow Side Effects","libyul", "controlFlowSideEffects",false, false, &yul::test::ControlFlowSideEffectsTest::create}, {"Function Side Effects", "libyul", "functionSideEffects", false, false, &yul::test::FunctionSideEffects::create}, {"Yul Syntax", "libyul", "yulSyntaxTests", false, false, &yul::test::SyntaxTest::create}, {"EVM Code Transform", "libyul", "evmCodeTransform", false, false, &yul::test::EVMCodeTransformTest::create, {"nooptions"}}, @@ -72,7 +73,8 @@ Testsuite const g_interactiveTestsuites[] = { {"JSON AST", "libsolidity", "ASTJSON", false, false, &ASTJSONTest::create}, {"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create}, {"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create}, - {"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create} + {"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create}, + {"Ewasm Translation", "libyul", "ewasmTranslationTests", false, false, &yul::test::EwasmTranslationTest::create} }; } diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 537ab516e..6fcd684f4 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -87,6 +87,10 @@ void runTestCase(TestCase::Config const& _config, TestCase::TestCaseCreator cons { BOOST_ERROR("Exception during extracted test: " << boost::diagnostic_information(_e)); } + catch (...) + { + BOOST_ERROR("Unknown exception during extracted test: " << boost::current_exception_diagnostic_information()); + } } int registerTests( diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index c413eef0f..1304da8af 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -424,7 +424,8 @@ printTask "Compiling various other contracts and libraries..." do echo " - $dir" cd "$dir" - compileFull --expect-warnings ./*.sol ./*/*.sol + # shellcheck disable=SC2046 # These file names are not supposed to contain spaces. + compileFull --expect-warnings $(find . -name '*.sol') cd .. done ) diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/args b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/args new file mode 100644 index 000000000..77f60c746 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/args @@ -0,0 +1 @@ +--ir --ir-optimized --asm --optimize --debug-info all diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/input.sol b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/input.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/input.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output new file mode 100644 index 000000000..31b0ae463 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all/output @@ -0,0 +1,213 @@ + +======= debug_info_in_yul_and_evm_asm_print_all/input.sol:C ======= +EVM assembly: + /* "debug_info_in_yul_and_evm_asm_print_all/input.sol":60:101 contract C {... */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert +tag_1: + pop + dataSize(sub_0) + dup1 + dataOffset(sub_0) + 0x00 + codecopy + 0x00 + return +stop + +sub_0: assembly { + /* "debug_info_in_yul_and_evm_asm_print_all/input.sol":60:101 contract C {... */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert + tag_1: + pop + jumpi(tag_2, lt(calldatasize, 0x04)) + shr(0xe0, calldataload(0x00)) + dup1 + 0x26121ff0 + eq + tag_3 + jumpi + tag_2: + 0x00 + dup1 + revert + /* "debug_info_in_yul_and_evm_asm_print_all/input.sol":77:99 function f() public {} */ + tag_3: + stop + + auxdata: +} + +IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:"debug_info_in_yul_and_evm_asm_print_all/input.sol" +object "C_6" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 "contract C {..." + function constructor_C_6() { + + /// @src 0:60:101 "contract C {..." + + } + /// @src 0:60:101 "contract C {..." + + } + /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_all/input.sol" + object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + + } + /// @src 0:60:101 "contract C {..." + + } + + data ".metadata" hex"" + } + +} + + +Optimized IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:"debug_info_in_yul_and_evm_asm_print_all/input.sol" +object "C_6" { + code { + { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("C_6_deployed") + codecopy(128, dataoffset("C_6_deployed"), _1) + return(128, _1) + } + } + /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_all/input.sol" + object "C_6_deployed" { + code { + { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(128, _1) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/args b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/args new file mode 100644 index 000000000..e0c752a3a --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/args @@ -0,0 +1 @@ +--ir --ir-optimized --asm --optimize --debug-info location,all,none diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/err b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/err new file mode 100644 index 000000000..99ed59cc0 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/err @@ -0,0 +1 @@ +Invalid value for --debug-info option: location,all,none diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/exit b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/exit similarity index 100% rename from test/cmdlineTests/yul_optimizer_steps_invalid_nesting/exit rename to test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/exit diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/input.sol b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_all_and_none/input.sol new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/args b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/args new file mode 100644 index 000000000..6b47cc2c3 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/args @@ -0,0 +1 @@ +--ir --ir-optimized --asm --optimize --debug-info location diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/input.sol b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/input.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/input.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output new file mode 100644 index 000000000..4d7210d37 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_location_only/output @@ -0,0 +1,212 @@ + +======= debug_info_in_yul_and_evm_asm_print_location_only/input.sol:C ======= +EVM assembly: + /* "debug_info_in_yul_and_evm_asm_print_location_only/input.sol":60:101 */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert +tag_1: + pop + dataSize(sub_0) + dup1 + dataOffset(sub_0) + 0x00 + codecopy + 0x00 + return +stop + +sub_0: assembly { + /* "debug_info_in_yul_and_evm_asm_print_location_only/input.sol":60:101 */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert + tag_1: + pop + jumpi(tag_2, lt(calldatasize, 0x04)) + shr(0xe0, calldataload(0x00)) + dup1 + 0x26121ff0 + eq + tag_3 + jumpi + tag_2: + 0x00 + dup1 + revert + /* "debug_info_in_yul_and_evm_asm_print_location_only/input.sol":77:99 */ + tag_3: + stop + + auxdata: +} + +IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:"debug_info_in_yul_and_evm_asm_print_location_only/input.sol" +object "C_6" { + code { + /// @src 0:60:101 + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 + function constructor_C_6() { + + /// @src 0:60:101 + + } + /// @src 0:60:101 + + } + /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_location_only/input.sol" + object "C_6_deployed" { + code { + /// @src 0:60:101 + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @src 0:77:99 + function fun_f_5() { + + } + /// @src 0:60:101 + + } + + data ".metadata" hex"" + } + +} + + +Optimized IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:"debug_info_in_yul_and_evm_asm_print_location_only/input.sol" +object "C_6" { + code { + { + /// @src 0:60:101 + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("C_6_deployed") + codecopy(128, dataoffset("C_6_deployed"), _1) + return(128, _1) + } + } + /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_location_only/input.sol" + object "C_6_deployed" { + code { + { + /// @src 0:60:101 + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(128, _1) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/args b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/args new file mode 100644 index 000000000..89896f68a --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/args @@ -0,0 +1 @@ +--ir --ir-optimized --asm --optimize --debug-info none diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/input.sol b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/input.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/input.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output new file mode 100644 index 000000000..0c0fbfa1e --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_none/output @@ -0,0 +1,201 @@ + +======= debug_info_in_yul_and_evm_asm_print_none/input.sol:C ======= +EVM assembly: + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert +tag_1: + pop + dataSize(sub_0) + dup1 + dataOffset(sub_0) + 0x00 + codecopy + 0x00 + return +stop + +sub_0: assembly { + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert + tag_1: + pop + jumpi(tag_2, lt(calldatasize, 0x04)) + shr(0xe0, calldataload(0x00)) + dup1 + 0x26121ff0 + eq + tag_3 + jumpi + tag_2: + 0x00 + dup1 + revert + tag_3: + stop + + auxdata: +} + +IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:"debug_info_in_yul_and_evm_asm_print_none/input.sol" +object "C_6" { + code { + + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + + return(_1, datasize("C_6_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function constructor_C_6() { + + } + + } + /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_none/input.sol" + object "C_6_deployed" { + code { + + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function fun_f_5() { + + } + + } + + data ".metadata" hex"" + } + +} + + +Optimized IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:"debug_info_in_yul_and_evm_asm_print_none/input.sol" +object "C_6" { + code { + { + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("C_6_deployed") + codecopy(128, dataoffset("C_6_deployed"), _1) + return(128, _1) + } + } + /// @use-src 0:"debug_info_in_yul_and_evm_asm_print_none/input.sol" + object "C_6_deployed" { + code { + { + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(128, _1) + } + } + revert(0, 0) + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/args b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/args new file mode 100644 index 000000000..9f1e80de2 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/args @@ -0,0 +1 @@ +--ir --ir-optimized --asm --optimize --debug-info snippet diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/err b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/err new file mode 100644 index 000000000..4cd94075a --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/err @@ -0,0 +1 @@ +To use 'snippet' with --debug-info you must select also 'location'. diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/exit b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/exit similarity index 100% rename from test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/exit rename to test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/exit diff --git a/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/input.sol b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/input.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/debug_info_in_yul_and_evm_asm_print_snippet_only/input.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output index a9dc1a290..b595a771e 100644 --- a/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output +++ b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output @@ -44,14 +44,6 @@ object "C_2" { /// @src 0:265:278 "contract C {}" mstore(64, 128) - if iszero(lt(calldatasize(), 4)) - { - let selector := shift_right_224_unsigned(calldataload(0)) - switch selector - - default {} - } - if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -175,7 +167,7 @@ object "D_27" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -413,14 +405,6 @@ object "D_27" { /// @src 0:265:278 "contract C {}" mstore(64, 128) - if iszero(lt(calldatasize(), 4)) - { - let selector := shift_right_224_unsigned(calldataload(0)) - switch selector - - default {} - } - if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -499,7 +483,7 @@ object "D_27" { revert(pos, returndatasize()) } mstore(add(allocate_memory_array_string(), 32), "/*") - let memPtr := allocate_memory_array_string_482() + let memPtr := allocate_memory_array_string_480() mstore(add(memPtr, 32), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b) mstore(add(memPtr, 64), shl(200, 0x2e2e2e22202a2f)) let memPos := mload(64) @@ -540,7 +524,7 @@ object "D_27" { memPtr := memPtr_1 mstore(memPtr_1, 2) } - function allocate_memory_array_string_482() -> memPtr + function allocate_memory_array_string_480() -> memPtr { let memPtr_1 := mload(64) let newFreePtr := add(memPtr_1, 96) diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index c4b71dcac..9c3efdc1f 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -63,7 +63,7 @@ object "C_81" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/linker_mode_output_selection_invalid/args b/test/cmdlineTests/linker_mode_output_selection_invalid/args new file mode 100644 index 000000000..ded0d6efc --- /dev/null +++ b/test/cmdlineTests/linker_mode_output_selection_invalid/args @@ -0,0 +1 @@ +--link --asm --asm-json --opcodes --bin --bin-runtime --abi --ir --ir-optimized --ewasm --hashes --userdoc --devdoc --metadata --storage-layout diff --git a/test/cmdlineTests/linker_mode_output_selection_invalid/err b/test/cmdlineTests/linker_mode_output_selection_invalid/err new file mode 100644 index 000000000..c84a12d97 --- /dev/null +++ b/test/cmdlineTests/linker_mode_output_selection_invalid/err @@ -0,0 +1 @@ +The following outputs are not supported in linker mode: --abi, --asm, --asm-json, --bin, --bin-runtime, --devdoc, --ewasm, --hashes, --ir, --ir-optimized, --metadata, --opcodes, --storage-layout, --userdoc. diff --git a/test/cmdlineTests/linker_mode_output_selection_invalid/exit b/test/cmdlineTests/linker_mode_output_selection_invalid/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/linker_mode_output_selection_invalid/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/linker_mode_output_selection_invalid/input.bin b/test/cmdlineTests/linker_mode_output_selection_invalid/input.bin new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index 73c9cc1aa..44852d1a8 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -49,7 +49,7 @@ object "C_59" { for { } lt(src, srcEnd) { src := add(src, _2) } { if slt(sub(calldatasize(), src), _2) { revert(_1, _1) } - let value := allocate_memory_1174() + let value := allocate_memory_1172() mstore(value, calldataload(src)) mstore(dst, value) dst := add(dst, _2) @@ -67,7 +67,7 @@ object "C_59" { mstore(4, 0x41) revert(0, 0x24) } - function allocate_memory_1174() -> memPtr + function allocate_memory_1172() -> memPtr { memPtr := mload(64) let newFreePtr := add(memPtr, 32) diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index 718cf0ba9..9ca27eac4 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -78,7 +78,7 @@ object "C_15" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/standard_cli_output_selection_invalid/args b/test/cmdlineTests/standard_cli_output_selection_invalid/args new file mode 100644 index 000000000..f2deb3847 --- /dev/null +++ b/test/cmdlineTests/standard_cli_output_selection_invalid/args @@ -0,0 +1 @@ +--ast-compact-json --asm --asm-json --opcodes --bin --bin-runtime --abi --ir --ir-optimized --ewasm --hashes --userdoc --devdoc --metadata --storage-layout diff --git a/test/cmdlineTests/standard_cli_output_selection_invalid/err b/test/cmdlineTests/standard_cli_output_selection_invalid/err new file mode 100644 index 000000000..d6ed4d572 --- /dev/null +++ b/test/cmdlineTests/standard_cli_output_selection_invalid/err @@ -0,0 +1 @@ +The following outputs are not supported in standard JSON mode: --abi, --asm, --asm-json, --ast-compact-json, --bin, --bin-runtime, --devdoc, --ewasm, --hashes, --ir, --ir-optimized, --metadata, --opcodes, --storage-layout, --userdoc. diff --git a/test/cmdlineTests/standard_cli_output_selection_invalid/exit b/test/cmdlineTests/standard_cli_output_selection_invalid/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/standard_cli_output_selection_invalid/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_cli_output_selection_invalid/input.json b/test/cmdlineTests/standard_cli_output_selection_invalid/input.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/args b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/in.sol b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/in.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/input.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/input.json new file mode 100644 index 000000000..3059e1ecd --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/input.json @@ -0,0 +1,13 @@ +{ + "language": "Solidity", + "sources": { + "C": {"urls": ["standard_debug_info_in_yul_and_evm_asm_print_all/in.sol"]} + }, + "settings": { + "debug": {"debugInfo": ["*"]}, + "optimizer": {"enabled": true}, + "outputSelection": { + "*": {"*": ["ir", "irOptimized", "evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json new file mode 100644 index 000000000..3c630bb2d --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_all/output.json @@ -0,0 +1,230 @@ +{ + "contracts": + { + "C": + { + "C": + { + "evm": + { + "assembly": " /* \"C\":60:101 contract C {... */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert +tag_1: + pop + dataSize(sub_0) + dup1 + dataOffset(sub_0) + 0x00 + codecopy + 0x00 + return +stop + +sub_0: assembly { + /* \"C\":60:101 contract C {... */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert + tag_1: + pop + jumpi(tag_2, lt(calldatasize, 0x04)) + shr(0xe0, calldataload(0x00)) + dup1 + 0x26121ff0 + eq + tag_3 + jumpi + tag_2: + 0x00 + dup1 + revert + /* \"C\":77:99 function f() public {} */ + tag_3: + stop + + auxdata: +} +" + }, + "ir": "/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:\"C\" +object \"C_6\" { + code { + /// @src 0:60:101 \"contract C {...\" + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) + + return(_1, datasize(\"C_6_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 \"contract C {...\" + function constructor_C_6() { + + /// @src 0:60:101 \"contract C {...\" + + } + /// @src 0:60:101 \"contract C {...\" + + } + /// @use-src 0:\"C\" + object \"C_6_deployed\" { + code { + /// @src 0:60:101 \"contract C {...\" + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @ast-id 5 + /// @src 0:77:99 \"function f() public {}\" + function fun_f_5() { + + } + /// @src 0:60:101 \"contract C {...\" + + } + + data \".metadata\" hex\"\" + } + +} + +", + "irOptimized": "/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:\"C\" +object \"C_6\" { + code { + { + /// @src 0:60:101 \"contract C {...\" + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize(\"C_6_deployed\") + codecopy(128, dataoffset(\"C_6_deployed\"), _1) + return(128, _1) + } + } + /// @use-src 0:\"C\" + object \"C_6_deployed\" { + code { + { + /// @src 0:60:101 \"contract C {...\" + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(128, _1) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + } + }, + "sources": + { + "C": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/args b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/in.sol b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/in.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/input.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/input.json new file mode 100644 index 000000000..8e338322b --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/input.json @@ -0,0 +1,13 @@ +{ + "language": "Solidity", + "sources": { + "C": {"urls": ["standard_debug_info_in_yul_and_evm_asm_print_location_only/in.sol"]} + }, + "settings": { + "debug": {"debugInfo": ["location"]}, + "optimizer": {"enabled": true}, + "outputSelection": { + "*": {"*": ["ir", "irOptimized", "evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json new file mode 100644 index 000000000..1f728995d --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_location_only/output.json @@ -0,0 +1,229 @@ +{ + "contracts": + { + "C": + { + "C": + { + "evm": + { + "assembly": " /* \"C\":60:101 */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert +tag_1: + pop + dataSize(sub_0) + dup1 + dataOffset(sub_0) + 0x00 + codecopy + 0x00 + return +stop + +sub_0: assembly { + /* \"C\":60:101 */ + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert + tag_1: + pop + jumpi(tag_2, lt(calldatasize, 0x04)) + shr(0xe0, calldataload(0x00)) + dup1 + 0x26121ff0 + eq + tag_3 + jumpi + tag_2: + 0x00 + dup1 + revert + /* \"C\":77:99 */ + tag_3: + stop + + auxdata: +} +" + }, + "ir": "/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:\"C\" +object \"C_6\" { + code { + /// @src 0:60:101 + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) + + return(_1, datasize(\"C_6_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:60:101 + function constructor_C_6() { + + /// @src 0:60:101 + + } + /// @src 0:60:101 + + } + /// @use-src 0:\"C\" + object \"C_6_deployed\" { + code { + /// @src 0:60:101 + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @src 0:77:99 + function fun_f_5() { + + } + /// @src 0:60:101 + + } + + data \".metadata\" hex\"\" + } + +} + +", + "irOptimized": "/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:\"C\" +object \"C_6\" { + code { + { + /// @src 0:60:101 + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize(\"C_6_deployed\") + codecopy(128, dataoffset(\"C_6_deployed\"), _1) + return(128, _1) + } + } + /// @use-src 0:\"C\" + object \"C_6_deployed\" { + code { + { + /// @src 0:60:101 + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(128, _1) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + } + }, + "sources": + { + "C": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/args b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/in.sol b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/in.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/input.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/input.json new file mode 100644 index 000000000..c9184d944 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/input.json @@ -0,0 +1,13 @@ +{ + "language": "Solidity", + "sources": { + "C": {"urls": ["standard_debug_info_in_yul_and_evm_asm_print_none/in.sol"]} + }, + "settings": { + "debug": {"debugInfo": []}, + "optimizer": {"enabled": true}, + "outputSelection": { + "*": {"*": ["ir", "irOptimized", "evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json new file mode 100644 index 000000000..8d19f60a3 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_none/output.json @@ -0,0 +1,218 @@ +{ + "contracts": + { + "C": + { + "C": + { + "evm": + { + "assembly": " mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert +tag_1: + pop + dataSize(sub_0) + dup1 + dataOffset(sub_0) + 0x00 + codecopy + 0x00 + return +stop + +sub_0: assembly { + mstore(0x40, 0x80) + callvalue + dup1 + iszero + tag_1 + jumpi + 0x00 + dup1 + revert + tag_1: + pop + jumpi(tag_2, lt(calldatasize, 0x04)) + shr(0xe0, calldataload(0x00)) + dup1 + 0x26121ff0 + eq + tag_3 + jumpi + tag_2: + 0x00 + dup1 + revert + tag_3: + stop + + auxdata: +} +" + }, + "ir": "/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:\"C\" +object \"C_6\" { + code { + + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_6() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) + + return(_1, datasize(\"C_6_deployed\")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function constructor_C_6() { + + } + + } + /// @use-src 0:\"C\" + object \"C_6_deployed\" { + code { + + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + fun_f_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple__to__fromStack(memPos ) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function fun_f_5() { + + } + + } + + data \".metadata\" hex\"\" + } + +} + +", + "irOptimized": "/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:\"C\" +object \"C_6\" { + code { + { + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize(\"C_6_deployed\") + codecopy(128, dataoffset(\"C_6_deployed\"), _1) + return(128, _1) + } + } + /// @use-src 0:\"C\" + object \"C_6_deployed\" { + code { + { + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + return(128, _1) + } + } + revert(0, 0) + } + } + data \".metadata\" hex\"\" + } +} +" + } + } + }, + "sources": + { + "C": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/args b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/in.sol b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/in.sol new file mode 100644 index 000000000..415509ef9 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +pragma solidity >=0.0; + +contract C { + function f() public {} +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/input.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/input.json new file mode 100644 index 000000000..962688913 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/input.json @@ -0,0 +1,13 @@ +{ + "language": "Solidity", + "sources": { + "C": {"urls": ["standard_debug_info_in_yul_and_evm_asm_print_snippet_only/in.sol"]} + }, + "settings": { + "debug": {"debugInfo": ["snippet"]}, + "optimizer": {"enabled": true}, + "outputSelection": { + "*": {"*": ["ir", "irOptimized", "evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/output.json b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/output.json new file mode 100644 index 000000000..fb7f199a7 --- /dev/null +++ b/test/cmdlineTests/standard_debug_info_in_yul_and_evm_asm_print_snippet_only/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "To use 'snippet' with settings.debug.debugInfo you must select also 'location'.", + "message": "To use 'snippet' with settings.debug.debugInfo you must select also 'location'.", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json index 0ba3b09a3..7a77d60f4 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json @@ -218,7 +218,7 @@ object \"C_54\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -639,7 +639,7 @@ object \"C_54\" { case 0x26121ff0 { if callvalue() { revert(_1, _1) } abi_decode(calldatasize()) - let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_568(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) + let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_566(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) /// @src 0:79:435 \"contract C...\" let memPos := mload(64) return(memPos, sub(abi_encode_int256(memPos, ret), memPos)) @@ -663,7 +663,7 @@ object \"C_54\" { if callvalue() { revert(_1, _1) } abi_decode(calldatasize()) let memPos_3 := mload(64) - return(memPos_3, sub(abi_encode_int256_567(memPos_3), memPos_3)) + return(memPos_3, sub(abi_encode_int256_565(memPos_3), memPos_3)) } } revert(0, 0) @@ -672,7 +672,7 @@ object \"C_54\" { { if slt(add(dataEnd, not(3)), 0) { revert(0, 0) } } - function abi_encode_int256_567(headStart) -> tail + function abi_encode_int256_565(headStart) -> tail { tail := add(headStart, 32) mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29) @@ -689,7 +689,7 @@ object \"C_54\" { mstore(4, 0x11) revert(0, 0x24) } - function checked_add_int256_568(y) -> sum + function checked_add_int256_566(y) -> sum { if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() } sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ y) @@ -1050,7 +1050,7 @@ object \"D_72\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -1479,7 +1479,7 @@ object \"D_72\" { case 0x26121ff0 { if callvalue() { revert(_1, _1) } abi_decode(calldatasize()) - let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_568(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) + let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_566(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) /// @src 1:91:166 \"contract D is C(3)...\" let memPos := mload(64) return(memPos, sub(abi_encode_int256(memPos, ret), memPos)) @@ -1503,7 +1503,7 @@ object \"D_72\" { if callvalue() { revert(_1, _1) } abi_decode(calldatasize()) let memPos_3 := mload(64) - return(memPos_3, sub(abi_encode_int256_567(memPos_3), memPos_3)) + return(memPos_3, sub(abi_encode_int256_565(memPos_3), memPos_3)) } } revert(0, 0) @@ -1512,7 +1512,7 @@ object \"D_72\" { { if slt(add(dataEnd, not(3)), 0) { revert(0, 0) } } - function abi_encode_int256_567(headStart) -> tail + function abi_encode_int256_565(headStart) -> tail { tail := add(headStart, 32) mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29) @@ -1529,7 +1529,7 @@ object \"D_72\" { mstore(4, 0x11) revert(0, 0x24) } - function checked_add_int256_568(y) -> sum + function checked_add_int256_566(y) -> sum { if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() } sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ y) diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index c636adcc4..78499140c 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -47,7 +47,6 @@ object \"C_7\" { } default { } } - if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { newValue := shr(224, value) } diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 2c01878f3..2da612abc 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -62,7 +62,7 @@ object \"C_7\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/standard_optimizer_invalid_detail_type/args b/test/cmdlineTests/standard_optimizer_invalid_detail_type/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_invalid_detail_type/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_invalid_detail_type/in.sol b/test/cmdlineTests/standard_optimizer_invalid_detail_type/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_invalid_detail_type/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json b/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json index 5e90f6d98..5d65bb2e2 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json +++ b/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json @@ -1,16 +1,9 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_invalid_detail_type/in.sol"]} }, - "settings": - { - "optimizer": { - "details": { "peephole": 7 } - } + "settings": { + "optimizer": {"details": {"peephole": 7}} } } diff --git a/test/cmdlineTests/standard_optimizer_invalid_detail_type/output.json b/test/cmdlineTests/standard_optimizer_invalid_detail_type/output.json index 15a65e586..2601dea6c 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_detail_type/output.json +++ b/test/cmdlineTests/standard_optimizer_invalid_detail_type/output.json @@ -1 +1,12 @@ -{"errors":[{"component":"general","formattedMessage":"\"settings.optimizer.details.peephole\" must be Boolean","message":"\"settings.optimizer.details.peephole\" must be Boolean","severity":"error","type":"JSONError"}]} +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "\"settings.optimizer.details.peephole\" must be Boolean", + "message": "\"settings.optimizer.details.peephole\" must be Boolean", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_invalid_details/args b/test/cmdlineTests/standard_optimizer_invalid_details/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_invalid_details/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_invalid_details/in.sol b/test/cmdlineTests/standard_optimizer_invalid_details/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_invalid_details/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_invalid_details/input.json b/test/cmdlineTests/standard_optimizer_invalid_details/input.json index eecfbd5e5..dbab578d6 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_details/input.json +++ b/test/cmdlineTests/standard_optimizer_invalid_details/input.json @@ -1,16 +1,9 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_invalid_details/in.sol"]} }, - "settings": - { - "optimizer": { - "details": { "notThere": true } - } + "settings": { + "optimizer": {"details": {"notThere": true}} } } diff --git a/test/cmdlineTests/standard_optimizer_invalid_details/output.json b/test/cmdlineTests/standard_optimizer_invalid_details/output.json index 20e62bc82..c7dfaf314 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_details/output.json +++ b/test/cmdlineTests/standard_optimizer_invalid_details/output.json @@ -1 +1,12 @@ -{"errors":[{"component":"general","formattedMessage":"Unknown key \"notThere\"","message":"Unknown key \"notThere\"","severity":"error","type":"JSONError"}]} +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "Unknown key \"notThere\"", + "message": "Unknown key \"notThere\"", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_no_yul/args b/test/cmdlineTests/standard_optimizer_no_yul/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_no_yul/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_no_yul/in.sol b/test/cmdlineTests/standard_optimizer_no_yul/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_no_yul/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_no_yul/input.json b/test/cmdlineTests/standard_optimizer_no_yul/input.json index a42299fbe..42ab767be 100644 --- a/test/cmdlineTests/standard_optimizer_no_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_no_yul/input.json @@ -1,17 +1,12 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_no_yul/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { "enabled": true, - "details": { "yul": false } + "details": {"yul": false} } } } diff --git a/test/cmdlineTests/standard_optimizer_no_yul/output.json b/test/cmdlineTests/standard_optimizer_no_yul/output.json index 59b90c8cc..acf3b74ef 100644 --- a/test/cmdlineTests/standard_optimizer_no_yul/output.json +++ b/test/cmdlineTests/standard_optimizer_no_yul/output.json @@ -1 +1,9 @@ -{"sources":{"A":{"id":0}}} +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yul/args b/test/cmdlineTests/standard_optimizer_yul/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yul/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yul/in.sol b/test/cmdlineTests/standard_optimizer_yul/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yul/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yul/input.json b/test/cmdlineTests/standard_optimizer_yul/input.json index 5e81a6091..cf40ef970 100644 --- a/test/cmdlineTests/standard_optimizer_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_yul/input.json @@ -1,14 +1,9 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yul/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { "enabled": true } diff --git a/test/cmdlineTests/standard_optimizer_yul/output.json b/test/cmdlineTests/standard_optimizer_yul/output.json index 59b90c8cc..acf3b74ef 100644 --- a/test/cmdlineTests/standard_optimizer_yul/output.json +++ b/test/cmdlineTests/standard_optimizer_yul/output.json @@ -1 +1,9 @@ -{"sources":{"A":{"id":0}}} +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails/args b/test/cmdlineTests/standard_optimizer_yulDetails/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails/input.json b/test/cmdlineTests/standard_optimizer_yulDetails/input.json index 842468bca..6cdf504fd 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails/input.json @@ -1,16 +1,14 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { - "details": { "yul": true, "yulDetails": {} } + "details": { + "yul": true, + "yulDetails": {} + } } } } diff --git a/test/cmdlineTests/standard_optimizer_yulDetails/output.json b/test/cmdlineTests/standard_optimizer_yulDetails/output.json index 59b90c8cc..acf3b74ef 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails/output.json @@ -1 +1,9 @@ -{"sources":{"A":{"id":0}}} +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/args b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json index 2581aeb71..4aba68350 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json @@ -1,16 +1,14 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_no_object/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { - "details": { "yul": true, "yulDetails": 7 } + "details": { + "yul": true, + "yulDetails": 7 + } } } } diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/output.json index 35638adf0..86a0c8698 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/output.json @@ -1 +1,12 @@ -{"errors":[{"component":"general","formattedMessage":"\"settings.optimizer.details.yulDetails\" must be an object","message":"\"settings.optimizer.details.yulDetails\" must be an object","severity":"error","type":"JSONError"}]} +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "\"settings.optimizer.details.yulDetails\" must be an object", + "message": "\"settings.optimizer.details.yulDetails\" must be an object", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json index 0dcdab6c2..584b8bf83 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json @@ -1,14 +1,9 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { "details": { "yul": true, diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/output.json index 59b90c8cc..acf3b74ef 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/output.json @@ -1 +1,9 @@ -{"sources":{"A":{"id":0}}} +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json index 427566764..48de0cce3 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json @@ -1,14 +1,9 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { "details": { "yul": true, diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/output.json index 84711c002..d4f6ef3a7 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/output.json @@ -1 +1,12 @@ -{"errors":[{"component":"general","formattedMessage":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": 'b' is not a valid step abbreviation","message":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": 'b' is not a valid step abbreviation","severity":"error","type":"JSONError"}]} +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": 'b' is not a valid step abbreviation", + "message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": 'b' is not a valid step abbreviation", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json deleted file mode 100644 index 851e132e8..000000000 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } - }, - "settings": - { - "optimizer": { - "details": { - "yul": true, - "yulDetails": { - "optimizerSteps": "a[a][aa[aa]]a" - } - } - } - } -} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/output.json deleted file mode 100644 index 409fd755f..000000000 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/output.json +++ /dev/null @@ -1 +0,0 @@ -{"errors":[{"component":"general","formattedMessage":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Nested brackets are not supported","message":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Nested brackets are not supported","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/input.json new file mode 100644 index 000000000..2baf7a723 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_nested_brackets/in.sol"]} + }, + "settings": { + "optimizer": { + "details": { + "yul": true, + "yulDetails": { + "optimizerSteps": "a[[a][[aa]aa[aa]][]]aaa[aa[aa[aa]]]a[a][a][a]a[a]" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/output.json new file mode 100644 index 000000000..acf3b74ef --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nested_brackets/output.json @@ -0,0 +1,9 @@ +{ + "sources": + { + "A": + { + "id": 0 + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/input.json new file mode 100644 index 000000000..1c055d915 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/in.sol"]} + }, + "settings": { + "optimizer": { + "details": { + "yul": true, + "yulDetails": { + "optimizerSteps": "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[a]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/output.json new file mode 100644 index 000000000..e06e14205 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_nesting_too_deep/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Brackets nested too deep", + "message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Brackets nested too deep", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json index 11bc9ca62..e6f2abaa2 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json @@ -1,14 +1,9 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_type/in.sol"]} }, - "settings": - { + "settings": { "optimizer": { "details": { "yul": true, diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/output.json index d18de5299..d6f9a9df8 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/output.json @@ -1 +1,12 @@ -{"errors":[{"component":"general","formattedMessage":"\"settings.optimizer.details.optimizerSteps\" must be a string","message":"\"settings.optimizer.details.optimizerSteps\" must be a string","severity":"error","type":"JSONError"}]} +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "\"settings.optimizer.details.optimizerSteps\" must be a string", + "message": "\"settings.optimizer.details.optimizerSteps\" must be a string", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json deleted file mode 100644 index 79c52e6dd..000000000 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } - }, - "settings": - { - "optimizer": { - "details": { - "yul": true, - "yulDetails": { - "optimizerSteps": "a[a][" - } - } - } - } -} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/output.json deleted file mode 100644 index d1843709b..000000000 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/output.json +++ /dev/null @@ -1 +0,0 @@ -{"errors":[{"component":"general","formattedMessage":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets","message":"Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/input.json new file mode 100644 index 000000000..e3cd50027 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/in.sol"]} + }, + "settings": { + "optimizer": { + "details": { + "yul": true, + "yulDetails": { + "optimizerSteps": "a]a][" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/output.json new file mode 100644 index 000000000..316529b0d --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_closing_bracket/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets", + "message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/args b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/input.json new file mode 100644 index 000000000..6cf7a2334 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/input.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/in.sol"]} + }, + "settings": { + "optimizer": { + "details": { + "yul": true, + "yulDetails": { + "optimizerSteps": "a[a][" + } + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/output.json new file mode 100644 index 000000000..316529b0d --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_opening_bracket/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets", + "message": "Invalid optimizer step sequence in \"settings.optimizer.details.optimizerSteps\": Unbalanced brackets", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/args b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/args new file mode 100644 index 000000000..a905f1fe6 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/in.sol b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/in.sol new file mode 100644 index 000000000..9e5350072 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/in.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f() public pure {} +} diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json index cac3c068b..abd8cc0c8 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json @@ -1,16 +1,10 @@ { "language": "Solidity", - "sources": - { - "A": - { - "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" - } + "sources": { + "A": {"urls": ["standard_optimizer_yulDetails_optimiserSteps_without_yul/in.sol"]} }, - "settings": - { - "optimizer": { - "details": { "yulDetails": 7 } + "settings": { + "optimizer": {"details": {"yulDetails": 7} } } } diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/output.json b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/output.json index c44794cc1..4e6d7b6f4 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/output.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/output.json @@ -1 +1,12 @@ -{"errors":[{"component":"general","formattedMessage":"\"Providing yulDetails requires Yul optimizer to be enabled.","message":"\"Providing yulDetails requires Yul optimizer to be enabled.","severity":"error","type":"JSONError"}]} +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "\"Providing yulDetails requires Yul optimizer to be enabled.", + "message": "\"Providing yulDetails requires Yul optimizer to be enabled.", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index 9ae88b90c..4bf34fd7a 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -43,14 +43,6 @@ object \"C_3\" { /// @src 0:79:92 \"contract C {}\" mstore(64, 128) - if iszero(lt(calldatasize(), 4)) - { - let selector := shift_right_224_unsigned(calldataload(0)) - switch selector - - default {} - } - if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -139,7 +131,7 @@ object \"D_16\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { @@ -253,14 +245,6 @@ object \"D_16\" { /// @src 0:79:92 \"contract C {}\" mstore(64, 128) - if iszero(lt(calldatasize(), 4)) - { - let selector := shift_right_224_unsigned(calldataload(0)) - switch selector - - default {} - } - if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/standard_yul_debug_info_print_all/args b/test/cmdlineTests/standard_yul_debug_info_print_all/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_all/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_yul_debug_info_print_all/in.yul b/test/cmdlineTests/standard_yul_debug_info_print_all/in.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_all/in.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_all/input.json b/test/cmdlineTests/standard_yul_debug_info_print_all/input.json new file mode 100644 index 000000000..1e6ed81a4 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_all/input.json @@ -0,0 +1,12 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_all/in.yul"]} + }, + "settings": { + "debug": {"debugInfo": ["*"]}, + "outputSelection": { + "*": {"*": ["evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_all/output.json b/test/cmdlineTests/standard_yul_debug_info_print_all/output.json new file mode 100644 index 000000000..b57bc9188 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_all/output.json @@ -0,0 +1,36 @@ +{ + "contracts": + { + "C": + { + "C_6_deployed": + { + "evm": + { + "assembly": " /* \"input.sol\":60:101 */ + mstore(0x40, 0x80) + tag_2 + tag_1 + jump\t// in +tag_2: + /* \"input.sol\":77:99 */ + jump(tag_3) +tag_1: + jump\t// out +tag_3: +" + } + } + } + }, + "errors": + [ + { + "component": "general", + "formattedMessage": "Yul is still experimental. Please use the output with care.", + "message": "Yul is still experimental. Please use the output with care.", + "severity": "warning", + "type": "Warning" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_location_only/args b/test/cmdlineTests/standard_yul_debug_info_print_location_only/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_location_only/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_yul_debug_info_print_location_only/in.yul b/test/cmdlineTests/standard_yul_debug_info_print_location_only/in.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_location_only/in.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_location_only/input.json b/test/cmdlineTests/standard_yul_debug_info_print_location_only/input.json new file mode 100644 index 000000000..867bc6e70 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_location_only/input.json @@ -0,0 +1,12 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_location_only/in.yul"]} + }, + "settings": { + "debug": {"debugInfo": ["location"]}, + "outputSelection": { + "*": {"*": ["evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json b/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json new file mode 100644 index 000000000..0ce9fd2de --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_location_only/output.json @@ -0,0 +1,36 @@ +{ + "contracts": + { + "C": + { + "C_6_deployed": + { + "evm": + { + "assembly": " /* \"input.sol\":60:101 */ + mstore(0x40, 0x80) + tag_2 + tag_1 + jump\t// in +tag_2: + /* \"input.sol\":77:99 */ + jump(tag_3) +tag_1: + jump\t// out +tag_3: +" + } + } + } + }, + "errors": + [ + { + "component": "general", + "formattedMessage": "Yul is still experimental. Please use the output with care.", + "message": "Yul is still experimental. Please use the output with care.", + "severity": "warning", + "type": "Warning" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_none/args b/test/cmdlineTests/standard_yul_debug_info_print_none/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_none/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_yul_debug_info_print_none/in.yul b/test/cmdlineTests/standard_yul_debug_info_print_none/in.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_none/in.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_none/input.json b/test/cmdlineTests/standard_yul_debug_info_print_none/input.json new file mode 100644 index 000000000..705cf3879 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_none/input.json @@ -0,0 +1,12 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_none/in.yul"]} + }, + "settings": { + "debug": {"debugInfo": []}, + "outputSelection": { + "*": {"*": ["evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_none/output.json b/test/cmdlineTests/standard_yul_debug_info_print_none/output.json new file mode 100644 index 000000000..8203ee0a2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_none/output.json @@ -0,0 +1,34 @@ +{ + "contracts": + { + "C": + { + "C_6_deployed": + { + "evm": + { + "assembly": " mstore(0x40, 0x80) + tag_2 + tag_1 + jump\t// in +tag_2: + jump(tag_3) +tag_1: + jump\t// out +tag_3: +" + } + } + } + }, + "errors": + [ + { + "component": "general", + "formattedMessage": "Yul is still experimental. Please use the output with care.", + "message": "Yul is still experimental. Please use the output with care.", + "severity": "warning", + "type": "Warning" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/args b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/in.yul b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/in.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/in.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/input.json b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/input.json new file mode 100644 index 000000000..ee247218f --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/input.json @@ -0,0 +1,12 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["standard_yul_debug_info_print_snippet_only/in.yul"]} + }, + "settings": { + "debug": {"debugInfo": ["snippet"]}, + "outputSelection": { + "*": {"*": ["evm.assembly"]} + } + } +} diff --git a/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/output.json b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/output.json new file mode 100644 index 000000000..fb7f199a7 --- /dev/null +++ b/test/cmdlineTests/standard_yul_debug_info_print_snippet_only/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "To use 'snippet' with settings.debug.debugInfo you must select also 'location'.", + "message": "To use 'snippet' with settings.debug.debugInfo you must select also 'location'.", + "severity": "error", + "type": "JSONError" + } + ] +} diff --git a/test/cmdlineTests/strict_asm_debug_info_print_all/args b/test/cmdlineTests/strict_asm_debug_info_print_all/args new file mode 100644 index 000000000..cfe8a15a2 --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_all/args @@ -0,0 +1 @@ +--strict-assembly --debug-info all diff --git a/test/cmdlineTests/strict_asm_debug_info_print_all/err b/test/cmdlineTests/strict_asm_debug_info_print_all/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_all/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_debug_info_print_all/input.yul b/test/cmdlineTests/strict_asm_debug_info_print_all/input.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_all/input.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/strict_asm_debug_info_print_all/output b/test/cmdlineTests/strict_asm_debug_info_print_all/output new file mode 100644 index 000000000..e83614b62 --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_all/output @@ -0,0 +1,32 @@ + +======= strict_asm_debug_info_print_all/input.yul (EVM) ======= + +Pretty printed source: +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 + mstore(64, 128) + fun_f_5() + /// @src 0:77:99 + function fun_f_5() + { } + } +} + + +Binary representation: +6080604052600a600e565b6010565b565b + +Text representation: + /* "input.sol":60:101 */ + mstore(0x40, 0x80) + tag_2 + tag_1 + jump // in +tag_2: + /* "input.sol":77:99 */ + jump(tag_3) +tag_1: + jump // out +tag_3: diff --git a/test/cmdlineTests/strict_asm_debug_info_print_location_only/args b/test/cmdlineTests/strict_asm_debug_info_print_location_only/args new file mode 100644 index 000000000..0d6ad325b --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_location_only/args @@ -0,0 +1 @@ +--strict-assembly --debug-info location diff --git a/test/cmdlineTests/strict_asm_debug_info_print_location_only/err b/test/cmdlineTests/strict_asm_debug_info_print_location_only/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_location_only/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_debug_info_print_location_only/input.yul b/test/cmdlineTests/strict_asm_debug_info_print_location_only/input.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_location_only/input.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/strict_asm_debug_info_print_location_only/output b/test/cmdlineTests/strict_asm_debug_info_print_location_only/output new file mode 100644 index 000000000..a4fd0e494 --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_location_only/output @@ -0,0 +1,32 @@ + +======= strict_asm_debug_info_print_location_only/input.yul (EVM) ======= + +Pretty printed source: +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 + mstore(64, 128) + fun_f_5() + /// @src 0:77:99 + function fun_f_5() + { } + } +} + + +Binary representation: +6080604052600a600e565b6010565b565b + +Text representation: + /* "input.sol":60:101 */ + mstore(0x40, 0x80) + tag_2 + tag_1 + jump // in +tag_2: + /* "input.sol":77:99 */ + jump(tag_3) +tag_1: + jump // out +tag_3: diff --git a/test/cmdlineTests/strict_asm_debug_info_print_none/args b/test/cmdlineTests/strict_asm_debug_info_print_none/args new file mode 100644 index 000000000..7e891dd86 --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_none/args @@ -0,0 +1 @@ +--strict-assembly --debug-info none diff --git a/test/cmdlineTests/strict_asm_debug_info_print_none/err b/test/cmdlineTests/strict_asm_debug_info_print_none/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_none/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_debug_info_print_none/input.yul b/test/cmdlineTests/strict_asm_debug_info_print_none/input.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_none/input.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/strict_asm_debug_info_print_none/output b/test/cmdlineTests/strict_asm_debug_info_print_none/output new file mode 100644 index 000000000..fc8841c9a --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_none/output @@ -0,0 +1,28 @@ + +======= strict_asm_debug_info_print_none/input.yul (EVM) ======= + +Pretty printed source: +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + mstore(64, 128) + fun_f_5() + function fun_f_5() + { } + } +} + + +Binary representation: +6080604052600a600e565b6010565b565b + +Text representation: + mstore(0x40, 0x80) + tag_2 + tag_1 + jump // in +tag_2: + jump(tag_3) +tag_1: + jump // out +tag_3: diff --git a/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/args b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/args new file mode 100644 index 000000000..362fd6515 --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/args @@ -0,0 +1 @@ +--strict-assembly --debug-info snippet diff --git a/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/err b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/err new file mode 100644 index 000000000..4cd94075a --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/err @@ -0,0 +1 @@ +To use 'snippet' with --debug-info you must select also 'location'. diff --git a/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/exit b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/input.yul b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/input.yul new file mode 100644 index 000000000..6d1ebe21b --- /dev/null +++ b/test/cmdlineTests/strict_asm_debug_info_print_snippet_only/input.yul @@ -0,0 +1,15 @@ +/// @use-src 0:"input.sol" +object "C_6_deployed" { + code { + /// @src 0:60:101 "contract C {..." + mstore(64, 128) + + // f() + fun_f_5() + + /// @src 0:77:99 "function f() public {}" + function fun_f_5() { + } + /// @src 0:60:101 "contract C {..." + } +} diff --git a/test/cmdlineTests/strict_asm_output_selection_invalid/args b/test/cmdlineTests/strict_asm_output_selection_invalid/args new file mode 100644 index 000000000..85814eb29 --- /dev/null +++ b/test/cmdlineTests/strict_asm_output_selection_invalid/args @@ -0,0 +1 @@ +--strict-assembly --asm --asm-json --opcodes --bin --bin-runtime --abi --ir --ir-optimized --ewasm --hashes --userdoc --devdoc --metadata --storage-layout diff --git a/test/cmdlineTests/strict_asm_output_selection_invalid/err b/test/cmdlineTests/strict_asm_output_selection_invalid/err new file mode 100644 index 000000000..736eb2c8a --- /dev/null +++ b/test/cmdlineTests/strict_asm_output_selection_invalid/err @@ -0,0 +1 @@ +The following outputs are not supported in assembler mode: --abi, --asm, --asm-json, --bin, --bin-runtime, --devdoc, --ewasm, --hashes, --ir, --ir-optimized, --metadata, --opcodes, --storage-layout, --userdoc. diff --git a/test/cmdlineTests/strict_asm_output_selection_invalid/exit b/test/cmdlineTests/strict_asm_output_selection_invalid/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/strict_asm_output_selection_invalid/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/strict_asm_output_selection_invalid/input.yul b/test/cmdlineTests/strict_asm_output_selection_invalid/input.yul new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index 18d02a0e9..a23730702 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -63,7 +63,7 @@ object "test_11" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/yul_optimize_runs/args b/test/cmdlineTests/yul_optimize_runs/args index b48e7aeed..033abe3bb 100644 --- a/test/cmdlineTests/yul_optimize_runs/args +++ b/test/cmdlineTests/yul_optimize_runs/args @@ -1 +1 @@ ---yul --yul-dialect evm --optimize --ir-optimized --optimize-runs 10000 +--yul --yul-dialect evm --optimize --optimize-runs 10000 diff --git a/test/cmdlineTests/yul_optimize_runs/input.yul b/test/cmdlineTests/yul_optimize_runs/input.yul index aeb7fd282..07c602a4a 100644 --- a/test/cmdlineTests/yul_optimize_runs/input.yul +++ b/test/cmdlineTests/yul_optimize_runs/input.yul @@ -7,7 +7,7 @@ object "RunsTest1" { object "Runtime" { code { let funcSel := shl(224, 0xabc12345) - mstore(0, funcSel) + sstore(0, funcSel) } } } diff --git a/test/cmdlineTests/yul_optimize_runs/output b/test/cmdlineTests/yul_optimize_runs/output index 20196dcb5..4c98ec30e 100644 --- a/test/cmdlineTests/yul_optimize_runs/output +++ b/test/cmdlineTests/yul_optimize_runs/output @@ -13,7 +13,7 @@ object "RunsTest1" { object "Runtime" { code { { - mstore(0, 0xabc1234500000000000000000000000000000000000000000000000000000000) + sstore(0, 0xabc1234500000000000000000000000000000000000000000000000000000000) } } } @@ -21,7 +21,7 @@ object "RunsTest1" { Binary representation: -602480600d600039806000f3fe7fabc1234500000000000000000000000000000000000000000000000000000000600052 +602480600d600039806000f3fe7fabc1234500000000000000000000000000000000000000000000000000000000600055 Text representation: /* "yul_optimize_runs/input.yul":106:125 */ @@ -47,6 +47,5 @@ sub_0: assembly { /* "yul_optimize_runs/input.yul":277:278 */ 0x00 /* "yul_optimize_runs/input.yul":270:288 */ - mstore + sstore } - diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index 478c844db..8e4cc7e88 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -31,16 +31,8 @@ object "C_7" { { /// @src 0:80:112 "contract C..." mstore(64, 128) - if iszero(lt(calldatasize(), 4)) - { - let selector := shift_right_unsigned(calldataload(0)) - pop(selector) - } - pop(iszero(calldatasize())) revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() } - function shift_right_unsigned(value) -> newValue - { newValue := shr(224, value) } function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } } diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/args b/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/args deleted file mode 100644 index 724fe4724..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/args +++ /dev/null @@ -1 +0,0 @@ ---ir-optimized --optimize --yul-optimizations a[a][aa[aa]]a diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/err b/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/err deleted file mode 100644 index 2f6d9ff47..000000000 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/err +++ /dev/null @@ -1 +0,0 @@ -Invalid optimizer step sequence in --yul-optimizations: Nested brackets are not supported diff --git a/test/cmdlineTests/yul_optimizer_steps_nested_brackets/args b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/args new file mode 100644 index 000000000..4b536761f --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations a[[a][[aa]aa[aa]][]]aaa[aa[aa[aa]]]a[a][a][a]a[a] diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/input.sol similarity index 100% rename from test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol rename to test/cmdlineTests/yul_optimizer_steps_nested_brackets/input.sol diff --git a/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output new file mode 100644 index 000000000..63f08a35d --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_nested_brackets/output @@ -0,0 +1,432 @@ +Optimized IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:"yul_optimizer_steps_nested_brackets/input.sol" +object "C_6" { + code { + { + /// @src 0:60:103 "contract C..." + mstore(64, 128) + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + constructor_C() + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + return(_1, datasize("C_6_deployed")) + } + function allocate_unbounded() -> memPtr + { + let memPtr_1 := mload(64) + let memPtr_2 := memPtr_1 + let memPtr_3 := memPtr_1 + let memPtr_4 := memPtr_1 + let memPtr_5 := memPtr_1 + let memPtr_6 := memPtr_1 + let memPtr_7 := memPtr_1 + let memPtr_8 := memPtr_1 + let memPtr_9 := memPtr_1 + let memPtr_10 := memPtr_1 + let memPtr_11 := memPtr_1 + let memPtr_12 := memPtr_1 + let memPtr_13 := memPtr_1 + let memPtr_14 := memPtr_1 + let memPtr_15 := memPtr_1 + let memPtr_16 := memPtr_1 + let memPtr_17 := memPtr_1 + let memPtr_18 := memPtr_1 + let memPtr_19 := memPtr_1 + let memPtr_20 := memPtr_1 + let memPtr_21 := memPtr_1 + let memPtr_22 := memPtr_1 + let memPtr_23 := memPtr_1 + let memPtr_24 := memPtr_1 + let memPtr_25 := memPtr_1 + let memPtr_26 := memPtr_1 + let memPtr_27 := memPtr_1 + let memPtr_28 := memPtr_1 + let memPtr_29 := memPtr_1 + let memPtr_30 := memPtr_1 + let memPtr_31 := memPtr_1 + let memPtr_32 := memPtr_1 + let memPtr_33 := memPtr_1 + let memPtr_34 := memPtr_1 + let memPtr_35 := memPtr_1 + let memPtr_36 := memPtr_1 + let memPtr_37 := memPtr_1 + let memPtr_38 := memPtr_1 + let memPtr_39 := memPtr_1 + let memPtr_40 := memPtr_1 + let memPtr_41 := memPtr_1 + let memPtr_42 := memPtr_1 + let memPtr_43 := memPtr_1 + let memPtr_44 := memPtr_1 + let memPtr_45 := memPtr_1 + let memPtr_46 := memPtr_1 + let memPtr_47 := memPtr_1 + let memPtr_48 := memPtr_1 + let memPtr_49 := memPtr_1 + let memPtr_50 := memPtr_1 + let memPtr_51 := memPtr_1 + let memPtr_52 := memPtr_1 + let memPtr_53 := memPtr_1 + let memPtr_54 := memPtr_1 + let memPtr_55 := memPtr_1 + let memPtr_56 := memPtr_1 + let memPtr_57 := memPtr_1 + let memPtr_58 := memPtr_1 + let memPtr_59 := memPtr_1 + let memPtr_60 := memPtr_1 + let memPtr_61 := memPtr_1 + let memPtr_62 := memPtr_1 + let memPtr_63 := memPtr_1 + let memPtr_64 := memPtr_1 + let memPtr_65 := memPtr_1 + let memPtr_66 := memPtr_1 + let memPtr_67 := memPtr_1 + let memPtr_68 := memPtr_1 + let memPtr_69 := memPtr_1 + let memPtr_70 := memPtr_1 + let memPtr_71 := memPtr_1 + let memPtr_72 := memPtr_1 + let memPtr_73 := memPtr_1 + let memPtr_74 := memPtr_1 + let memPtr_75 := memPtr_1 + let memPtr_76 := memPtr_1 + let memPtr_77 := memPtr_1 + let memPtr_78 := memPtr_1 + let memPtr_79 := memPtr_1 + let memPtr_80 := memPtr_1 + let memPtr_81 := memPtr_1 + let memPtr_82 := memPtr_1 + let memPtr_83 := memPtr_1 + let memPtr_84 := memPtr_1 + let memPtr_85 := memPtr_1 + let memPtr_86 := memPtr_1 + memPtr := memPtr_1 + } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + function constructor_C() + { } + } + /// @use-src 0:"yul_optimizer_steps_nested_brackets/input.sol" + object "C_6_deployed" { + code { + { + /// @src 0:60:103 "contract C..." + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_unsigned(calldataload(0)) + if eq(0x26121ff0, selector) + { + if callvalue() + { + revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + } + abi_decode(4, calldatasize()) + fun_f() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple(memPos) + return(memPos, sub(memEnd, memPos)) + } + } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + } + function shift_right_unsigned(value) -> newValue + { + let newValue_1 := shr(224, value) + let newValue_2 := newValue_1 + let newValue_3 := newValue_1 + let newValue_4 := newValue_1 + let newValue_5 := newValue_1 + let newValue_6 := newValue_1 + let newValue_7 := newValue_1 + let newValue_8 := newValue_1 + let newValue_9 := newValue_1 + let newValue_10 := newValue_1 + let newValue_11 := newValue_1 + let newValue_12 := newValue_1 + let newValue_13 := newValue_1 + let newValue_14 := newValue_1 + let newValue_15 := newValue_1 + let newValue_16 := newValue_1 + let newValue_17 := newValue_1 + let newValue_18 := newValue_1 + let newValue_19 := newValue_1 + let newValue_20 := newValue_1 + let newValue_21 := newValue_1 + let newValue_22 := newValue_1 + let newValue_23 := newValue_1 + let newValue_24 := newValue_1 + let newValue_25 := newValue_1 + let newValue_26 := newValue_1 + let newValue_27 := newValue_1 + let newValue_28 := newValue_1 + let newValue_29 := newValue_1 + let newValue_30 := newValue_1 + let newValue_31 := newValue_1 + let newValue_32 := newValue_1 + let newValue_33 := newValue_1 + let newValue_34 := newValue_1 + let newValue_35 := newValue_1 + let newValue_36 := newValue_1 + let newValue_37 := newValue_1 + let newValue_38 := newValue_1 + let newValue_39 := newValue_1 + let newValue_40 := newValue_1 + let newValue_41 := newValue_1 + let newValue_42 := newValue_1 + let newValue_43 := newValue_1 + let newValue_44 := newValue_1 + let newValue_45 := newValue_1 + let newValue_46 := newValue_1 + let newValue_47 := newValue_1 + let newValue_48 := newValue_1 + let newValue_49 := newValue_1 + let newValue_50 := newValue_1 + let newValue_51 := newValue_1 + let newValue_52 := newValue_1 + let newValue_53 := newValue_1 + let newValue_54 := newValue_1 + let newValue_55 := newValue_1 + let newValue_56 := newValue_1 + let newValue_57 := newValue_1 + let newValue_58 := newValue_1 + let newValue_59 := newValue_1 + let newValue_60 := newValue_1 + let newValue_61 := newValue_1 + let newValue_62 := newValue_1 + let newValue_63 := newValue_1 + let newValue_64 := newValue_1 + let newValue_65 := newValue_1 + let newValue_66 := newValue_1 + let newValue_67 := newValue_1 + let newValue_68 := newValue_1 + let newValue_69 := newValue_1 + let newValue_70 := newValue_1 + let newValue_71 := newValue_1 + let newValue_72 := newValue_1 + let newValue_73 := newValue_1 + let newValue_74 := newValue_1 + let newValue_75 := newValue_1 + let newValue_76 := newValue_1 + let newValue_77 := newValue_1 + let newValue_78 := newValue_1 + let newValue_79 := newValue_1 + let newValue_80 := newValue_1 + let newValue_81 := newValue_1 + let newValue_82 := newValue_1 + let newValue_83 := newValue_1 + let newValue_84 := newValue_1 + let newValue_85 := newValue_1 + let newValue_86 := newValue_1 + newValue := newValue_1 + } + function allocate_unbounded() -> memPtr + { + let memPtr_1 := mload(64) + let memPtr_2 := memPtr_1 + let memPtr_3 := memPtr_1 + let memPtr_4 := memPtr_1 + let memPtr_5 := memPtr_1 + let memPtr_6 := memPtr_1 + let memPtr_7 := memPtr_1 + let memPtr_8 := memPtr_1 + let memPtr_9 := memPtr_1 + let memPtr_10 := memPtr_1 + let memPtr_11 := memPtr_1 + let memPtr_12 := memPtr_1 + let memPtr_13 := memPtr_1 + let memPtr_14 := memPtr_1 + let memPtr_15 := memPtr_1 + let memPtr_16 := memPtr_1 + let memPtr_17 := memPtr_1 + let memPtr_18 := memPtr_1 + let memPtr_19 := memPtr_1 + let memPtr_20 := memPtr_1 + let memPtr_21 := memPtr_1 + let memPtr_22 := memPtr_1 + let memPtr_23 := memPtr_1 + let memPtr_24 := memPtr_1 + let memPtr_25 := memPtr_1 + let memPtr_26 := memPtr_1 + let memPtr_27 := memPtr_1 + let memPtr_28 := memPtr_1 + let memPtr_29 := memPtr_1 + let memPtr_30 := memPtr_1 + let memPtr_31 := memPtr_1 + let memPtr_32 := memPtr_1 + let memPtr_33 := memPtr_1 + let memPtr_34 := memPtr_1 + let memPtr_35 := memPtr_1 + let memPtr_36 := memPtr_1 + let memPtr_37 := memPtr_1 + let memPtr_38 := memPtr_1 + let memPtr_39 := memPtr_1 + let memPtr_40 := memPtr_1 + let memPtr_41 := memPtr_1 + let memPtr_42 := memPtr_1 + let memPtr_43 := memPtr_1 + let memPtr_44 := memPtr_1 + let memPtr_45 := memPtr_1 + let memPtr_46 := memPtr_1 + let memPtr_47 := memPtr_1 + let memPtr_48 := memPtr_1 + let memPtr_49 := memPtr_1 + let memPtr_50 := memPtr_1 + let memPtr_51 := memPtr_1 + let memPtr_52 := memPtr_1 + let memPtr_53 := memPtr_1 + let memPtr_54 := memPtr_1 + let memPtr_55 := memPtr_1 + let memPtr_56 := memPtr_1 + let memPtr_57 := memPtr_1 + let memPtr_58 := memPtr_1 + let memPtr_59 := memPtr_1 + let memPtr_60 := memPtr_1 + let memPtr_61 := memPtr_1 + let memPtr_62 := memPtr_1 + let memPtr_63 := memPtr_1 + let memPtr_64 := memPtr_1 + let memPtr_65 := memPtr_1 + let memPtr_66 := memPtr_1 + let memPtr_67 := memPtr_1 + let memPtr_68 := memPtr_1 + let memPtr_69 := memPtr_1 + let memPtr_70 := memPtr_1 + let memPtr_71 := memPtr_1 + let memPtr_72 := memPtr_1 + let memPtr_73 := memPtr_1 + let memPtr_74 := memPtr_1 + let memPtr_75 := memPtr_1 + let memPtr_76 := memPtr_1 + let memPtr_77 := memPtr_1 + let memPtr_78 := memPtr_1 + let memPtr_79 := memPtr_1 + let memPtr_80 := memPtr_1 + let memPtr_81 := memPtr_1 + let memPtr_82 := memPtr_1 + let memPtr_83 := memPtr_1 + let memPtr_84 := memPtr_1 + let memPtr_85 := memPtr_1 + let memPtr_86 := memPtr_1 + memPtr := memPtr_1 + } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() + { revert(0, 0) } + function abi_decode(headStart, dataEnd) + { + if slt(sub(dataEnd, headStart), 0) + { + revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() + } + } + function abi_encode_tuple(headStart) -> tail + { + let tail_1 := add(headStart, 0) + let tail_2 := tail_1 + let tail_3 := tail_1 + let tail_4 := tail_1 + let tail_5 := tail_1 + let tail_6 := tail_1 + let tail_7 := tail_1 + let tail_8 := tail_1 + let tail_9 := tail_1 + let tail_10 := tail_1 + let tail_11 := tail_1 + let tail_12 := tail_1 + let tail_13 := tail_1 + let tail_14 := tail_1 + let tail_15 := tail_1 + let tail_16 := tail_1 + let tail_17 := tail_1 + let tail_18 := tail_1 + let tail_19 := tail_1 + let tail_20 := tail_1 + let tail_21 := tail_1 + let tail_22 := tail_1 + let tail_23 := tail_1 + let tail_24 := tail_1 + let tail_25 := tail_1 + let tail_26 := tail_1 + let tail_27 := tail_1 + let tail_28 := tail_1 + let tail_29 := tail_1 + let tail_30 := tail_1 + let tail_31 := tail_1 + let tail_32 := tail_1 + let tail_33 := tail_1 + let tail_34 := tail_1 + let tail_35 := tail_1 + let tail_36 := tail_1 + let tail_37 := tail_1 + let tail_38 := tail_1 + let tail_39 := tail_1 + let tail_40 := tail_1 + let tail_41 := tail_1 + let tail_42 := tail_1 + let tail_43 := tail_1 + let tail_44 := tail_1 + let tail_45 := tail_1 + let tail_46 := tail_1 + let tail_47 := tail_1 + let tail_48 := tail_1 + let tail_49 := tail_1 + let tail_50 := tail_1 + let tail_51 := tail_1 + let tail_52 := tail_1 + let tail_53 := tail_1 + let tail_54 := tail_1 + let tail_55 := tail_1 + let tail_56 := tail_1 + let tail_57 := tail_1 + let tail_58 := tail_1 + let tail_59 := tail_1 + let tail_60 := tail_1 + let tail_61 := tail_1 + let tail_62 := tail_1 + let tail_63 := tail_1 + let tail_64 := tail_1 + let tail_65 := tail_1 + let tail_66 := tail_1 + let tail_67 := tail_1 + let tail_68 := tail_1 + let tail_69 := tail_1 + let tail_70 := tail_1 + let tail_71 := tail_1 + let tail_72 := tail_1 + let tail_73 := tail_1 + let tail_74 := tail_1 + let tail_75 := tail_1 + let tail_76 := tail_1 + let tail_77 := tail_1 + let tail_78 := tail_1 + let tail_79 := tail_1 + let tail_80 := tail_1 + let tail_81 := tail_1 + let tail_82 := tail_1 + let tail_83 := tail_1 + let tail_84 := tail_1 + let tail_85 := tail_1 + let tail_86 := tail_1 + tail := tail_1 + } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + { revert(0, 0) } + /// @ast-id 5 @src 0:74:101 "function f() public pure {}" + function fun_f() + { } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/args b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/args new file mode 100644 index 000000000..b2ff99d3f --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[a]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/err b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/err new file mode 100644 index 000000000..c8dc9697e --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/err @@ -0,0 +1 @@ +Invalid optimizer step sequence in --yul-optimizations: Brackets nested too deep diff --git a/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/exit b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol b/test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/input.sol similarity index 100% rename from test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol rename to test/cmdlineTests/yul_optimizer_steps_nesting_too_deep/input.sol diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/args b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/args new file mode 100644 index 000000000..04933d213 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/args @@ -0,0 +1 @@ +--ir-optimized --optimize --yul-optimizations a]a][ diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/err b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/err similarity index 100% rename from test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/err rename to test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/err diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/exit b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/input.sol b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/input.sol new file mode 100644 index 000000000..6923ca702 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_closing_bracket/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C +{ + function f() public pure {} +} diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/args b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/args similarity index 100% rename from test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/args rename to test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/args diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/err b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/err new file mode 100644 index 000000000..1da42b743 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/err @@ -0,0 +1 @@ +Invalid optimizer step sequence in --yul-optimizations: Unbalanced brackets diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/exit b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/input.sol b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/input.sol new file mode 100644 index 000000000..6923ca702 --- /dev/null +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_opening_bracket/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C +{ + function f() public pure {} +} diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index f68f984c7..ae7a926fe 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -62,7 +62,7 @@ object \"C_11\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index e2757135e..59a93a7bf 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -62,7 +62,7 @@ object \"C_11\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index c977d791d..79d35a338 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -62,7 +62,7 @@ object \"C_11\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 19428f29d..932a5c28c 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -62,7 +62,7 @@ object \"C_11\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index b17922a55..da8f873a3 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -62,7 +62,7 @@ object \"C_11\" { default {} } - if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() function shift_right_224_unsigned(value) -> newValue { diff --git a/test/formal/byte_big.py b/test/formal/byte_big.py index db11bc998..8e6dfd7ef 100644 --- a/test/formal/byte_big.py +++ b/test/formal/byte_big.py @@ -1,5 +1,6 @@ +from opcodes import BYTE from rule import Rule -from opcodes import * +from z3 import BitVec """ byte(A, X) -> 0 diff --git a/test/formal/byte_equivalence.py b/test/formal/byte_equivalence.py index 0f3638424..c607eca4c 100644 --- a/test/formal/byte_equivalence.py +++ b/test/formal/byte_equivalence.py @@ -1,5 +1,6 @@ +from opcodes import BYTE from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, Concat, Extract """ Checks that the byte opcode (implemented using shift) is equivalent to a diff --git a/test/formal/checked_int_add.py b/test/formal/checked_int_add.py index 6e74944e2..43368a98d 100644 --- a/test/formal/checked_int_add.py +++ b/test/formal/checked_int_add.py @@ -1,6 +1,7 @@ +from opcodes import AND, ISZERO, SGT, SLT, SUB from rule import Rule -from opcodes import * -from util import * +from util import BVSignedMax, BVSignedMin, BVSignedUpCast +from z3 import BitVec, BVAddNoOverflow, BVAddNoUnderflow, Not """ Overflow checked signed integer addition. diff --git a/test/formal/checked_int_div.py b/test/formal/checked_int_div.py index 2a36a9488..4c9d4e829 100644 --- a/test/formal/checked_int_div.py +++ b/test/formal/checked_int_div.py @@ -1,6 +1,7 @@ +from opcodes import AND, EQ, SUB from rule import Rule -from opcodes import * -from util import * +from util import BVSignedMin, BVSignedUpCast +from z3 import BitVec, BVSDivNoOverflow, Not """ Overflow checked signed integer division. diff --git a/test/formal/checked_int_mul_16.py b/test/formal/checked_int_mul_16.py index cc8743b1d..b2f9eb852 100644 --- a/test/formal/checked_int_mul_16.py +++ b/test/formal/checked_int_mul_16.py @@ -1,6 +1,7 @@ +from opcodes import AND, DIV, GT, SDIV, SGT, SLT from rule import Rule -from opcodes import * -from util import * +from util import BVSignedMax, BVSignedMin, BVSignedUpCast +from z3 import BVMulNoOverflow, BVMulNoUnderflow, BitVec, Not, Or """ Overflow checked signed integer multiplication. diff --git a/test/formal/checked_int_sub.py b/test/formal/checked_int_sub.py index 72a0a2109..ed292bbe0 100644 --- a/test/formal/checked_int_sub.py +++ b/test/formal/checked_int_sub.py @@ -1,6 +1,7 @@ +from opcodes import AND, ADD, ISZERO, SLT, SGT from rule import Rule -from opcodes import * -from util import * +from util import BVSignedMax, BVSignedMin, BVSignedUpCast +from z3 import BitVec, BVSubNoOverflow, BVSubNoUnderflow, Not """ Overflow checked signed integer subtraction. diff --git a/test/formal/checked_uint_add.py b/test/formal/checked_uint_add.py index 596fa04f0..e38b4dcdb 100644 --- a/test/formal/checked_uint_add.py +++ b/test/formal/checked_uint_add.py @@ -1,6 +1,7 @@ +from opcodes import GT, SUB from rule import Rule -from opcodes import * -from util import * +from util import BVUnsignedMax, BVUnsignedUpCast +from z3 import BitVec, BVAddNoOverflow, Not """ Overflow checked unsigned integer addition. diff --git a/test/formal/checked_uint_mul_16.py b/test/formal/checked_uint_mul_16.py index 6e8901799..1c60de47b 100644 --- a/test/formal/checked_uint_mul_16.py +++ b/test/formal/checked_uint_mul_16.py @@ -1,6 +1,7 @@ +from opcodes import AND, ISZERO, GT, DIV from rule import Rule -from opcodes import * -from util import * +from util import BVUnsignedUpCast, BVUnsignedMax +from z3 import BitVec, Not, BVMulNoOverflow """ Overflow checked unsigned integer multiplication. diff --git a/test/formal/checked_uint_sub.py b/test/formal/checked_uint_sub.py index b0f25b582..65bcf74a4 100644 --- a/test/formal/checked_uint_sub.py +++ b/test/formal/checked_uint_sub.py @@ -1,6 +1,7 @@ +from opcodes import LT from rule import Rule -from opcodes import * -from util import * +from util import BVUnsignedMax, BVUnsignedUpCast +from z3 import BVSubNoUnderflow, BitVec, Not """ Overflow checked unsigned integer subtraction. diff --git a/test/formal/combine_byte_shl.py b/test/formal/combine_byte_shl.py index e2a6034ff..f492cc18f 100644 --- a/test/formal/combine_byte_shl.py +++ b/test/formal/combine_byte_shl.py @@ -1,5 +1,6 @@ +from opcodes import BYTE, SHL from rule import Rule -from opcodes import * +from z3 import BitVec, ULE """ byte(A, shl(B, X)) diff --git a/test/formal/combine_byte_shr_1.py b/test/formal/combine_byte_shr_1.py index 4938e73f7..788319aa2 100644 --- a/test/formal/combine_byte_shr_1.py +++ b/test/formal/combine_byte_shr_1.py @@ -1,5 +1,6 @@ +from opcodes import BYTE, DIV, SHR from rule import Rule -from opcodes import * +from z3 import BitVec, UGE, ULE, ULT """ byte(A, shr(B, X)) diff --git a/test/formal/combine_byte_shr_2.py b/test/formal/combine_byte_shr_2.py index 4f9be05a4..d969c301b 100644 --- a/test/formal/combine_byte_shr_2.py +++ b/test/formal/combine_byte_shr_2.py @@ -1,5 +1,6 @@ +from opcodes import BYTE, SHR, DIV from rule import Rule -from opcodes import * +from z3 import BitVec, ULT """ byte(A, shr(B, X)) diff --git a/test/formal/combine_div_shl_one_32.py b/test/formal/combine_div_shl_one_32.py index 2ee7d2137..5cca7288b 100644 --- a/test/formal/combine_div_shl_one_32.py +++ b/test/formal/combine_div_shl_one_32.py @@ -1,5 +1,6 @@ +from opcodes import DIV, SHL, SHR from rule import Rule -from opcodes import * +from z3 import BitVec """ Rule: diff --git a/test/formal/combine_mul_shl_one_64.py b/test/formal/combine_mul_shl_one_64.py index 44d031b98..169cc5be0 100644 --- a/test/formal/combine_mul_shl_one_64.py +++ b/test/formal/combine_mul_shl_one_64.py @@ -1,5 +1,6 @@ +from opcodes import SHL, MUL from rule import Rule -from opcodes import * +from z3 import BitVec """ Rule: diff --git a/test/formal/combine_shl_shr_by_constant_64.py b/test/formal/combine_shl_shr_by_constant_64.py index fc7ec64e8..4d8e6a1f8 100644 --- a/test/formal/combine_shl_shr_by_constant_64.py +++ b/test/formal/combine_shl_shr_by_constant_64.py @@ -1,5 +1,6 @@ +from opcodes import AND, SHL, SHR from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, If, Int2BV, IntVal, UGT, ULT """ Rule: diff --git a/test/formal/combine_shr_shl_by_constant_64.py b/test/formal/combine_shr_shl_by_constant_64.py index c011a2616..5bc852574 100644 --- a/test/formal/combine_shr_shl_by_constant_64.py +++ b/test/formal/combine_shr_shl_by_constant_64.py @@ -1,5 +1,6 @@ +from opcodes import AND, SHL, SHR from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, If, Int2BV, IntVal, UGT, ULT """ Rule: diff --git a/test/formal/eq_sub.py b/test/formal/eq_sub.py index bf7518acf..76808bc3b 100644 --- a/test/formal/eq_sub.py +++ b/test/formal/eq_sub.py @@ -1,5 +1,6 @@ +from opcodes import EQ, ISZERO, SUB from rule import Rule -from opcodes import * +from z3 import BitVec """ Rule: diff --git a/test/formal/exp_neg_one.py b/test/formal/exp_neg_one.py index 88416496e..4dffb88b0 100644 --- a/test/formal/exp_neg_one.py +++ b/test/formal/exp_neg_one.py @@ -1,6 +1,7 @@ +from opcodes import AND, ISZERO, MOD, SUB from rule import Rule -from opcodes import * -from util import * +from util import BVUnsignedMax +from z3 import BitVec, BitVecVal, If """ Checking conversion of exp(-1, X) to sub(isZero(and(X, 1)), and(X, 1)) diff --git a/test/formal/exp_to_shl.py b/test/formal/exp_to_shl.py index 064d1af3e..499cf7c2f 100644 --- a/test/formal/exp_to_shl.py +++ b/test/formal/exp_to_shl.py @@ -1,6 +1,6 @@ +from opcodes import SHL from rule import Rule -from opcodes import * -from util import * +from z3 import BitVec, If """ Checking conversion of exp(2, X) to shl(X, 1) diff --git a/test/formal/move_and_across_shl_128.py b/test/formal/move_and_across_shl_128.py index d3f5c3a66..9e689b71e 100644 --- a/test/formal/move_and_across_shl_128.py +++ b/test/formal/move_and_across_shl_128.py @@ -1,5 +1,6 @@ +from opcodes import AND, SHL from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, ULT """ Rule: diff --git a/test/formal/move_and_across_shr_128.py b/test/formal/move_and_across_shr_128.py index df673ff59..592dc7742 100644 --- a/test/formal/move_and_across_shr_128.py +++ b/test/formal/move_and_across_shr_128.py @@ -1,5 +1,6 @@ +from opcodes import AND, SHR from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, ULT """ Rule: @@ -25,12 +26,12 @@ BitWidth = BitVecVal(n_bits, n_bits) rule.require(ULT(B, BitWidth)) # Non optimized result -nonopt_1 = SHR(B, AND(X, A)); -nonopt_2 = SHR(B, AND(A, X)); +nonopt_1 = SHR(B, AND(X, A)) +nonopt_2 = SHR(B, AND(A, X)) # Optimized result -Mask = SHR(B, A); -opt = AND(SHR(B, X), Mask); +Mask = SHR(B, A) +opt = AND(SHR(B, X), Mask) rule.check(nonopt_1, opt) rule.check(nonopt_2, opt) diff --git a/test/formal/move_and_inside_or.py b/test/formal/move_and_inside_or.py index 09dc35c51..48ec20dba 100644 --- a/test/formal/move_and_inside_or.py +++ b/test/formal/move_and_inside_or.py @@ -1,5 +1,7 @@ +from opcodes import AND, OR from rule import Rule -from opcodes import * +from z3 import BitVec + """ Rule: diff --git a/test/formal/opcodes.py b/test/formal/opcodes.py index 6098d01ed..103e57a14 100644 --- a/test/formal/opcodes.py +++ b/test/formal/opcodes.py @@ -1,4 +1,4 @@ -from z3 import * +from z3 import BitVecVal, BV2Int, If, LShR, UDiv, ULT, UGT, URem def ADD(x, y): return x + y diff --git a/test/formal/repeated_and.py b/test/formal/repeated_and.py index 2e8431b3c..2376ca34f 100644 --- a/test/formal/repeated_and.py +++ b/test/formal/repeated_and.py @@ -1,5 +1,6 @@ +from opcodes import AND from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal """ Rule: diff --git a/test/formal/repeated_or.py b/test/formal/repeated_or.py index c1b2ebd09..ba18e39aa 100644 --- a/test/formal/repeated_or.py +++ b/test/formal/repeated_or.py @@ -1,5 +1,6 @@ +from opcodes import OR from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal """ Rule: diff --git a/test/formal/replace_mul_by_shift.py b/test/formal/replace_mul_by_shift.py index 5a2c2dc14..3805af0dc 100644 --- a/test/formal/replace_mul_by_shift.py +++ b/test/formal/replace_mul_by_shift.py @@ -1,5 +1,6 @@ +from opcodes import DIV, MUL, SHL, SHR from rule import Rule -from opcodes import * +from z3 import BitVec """ Rule: diff --git a/test/formal/rule.py b/test/formal/rule.py index 9327f7e5a..ac0f0c8a6 100644 --- a/test/formal/rule.py +++ b/test/formal/rule.py @@ -1,6 +1,6 @@ import sys -from z3 import * +from z3 import sat, Solver, unknown, unsat class Rule: def __init__(self): diff --git a/test/formal/shl_workaround_8.py b/test/formal/shl_workaround_8.py index 2ca711cdf..19248574a 100644 --- a/test/formal/shl_workaround_8.py +++ b/test/formal/shl_workaround_8.py @@ -1,5 +1,6 @@ +from opcodes import SHL from rule import Rule -from opcodes import * +from z3 import BitVec, BV2Int, Int2BV, IntVal """ Shift left workaround that Solidity implements diff --git a/test/formal/signextend.py b/test/formal/signextend.py index 32d374261..ed285345d 100644 --- a/test/formal/signextend.py +++ b/test/formal/signextend.py @@ -1,5 +1,6 @@ +from opcodes import SIGNEXTEND from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, If, UGE, ULT """ Rule: @@ -34,4 +35,3 @@ rule3.check( SIGNEXTEND(A, SIGNEXTEND(B, X)), SIGNEXTEND(If(ULT(A, B), A, B), X) ) - diff --git a/test/formal/signextend_and.py b/test/formal/signextend_and.py index ae2b4bd2c..91fc14349 100644 --- a/test/formal/signextend_and.py +++ b/test/formal/signextend_and.py @@ -1,5 +1,6 @@ +from opcodes import SIGNEXTEND, AND from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, ULT """ Rule: diff --git a/test/formal/signextend_equivalence.py b/test/formal/signextend_equivalence.py index 1199fff47..3b8386e54 100644 --- a/test/formal/signextend_equivalence.py +++ b/test/formal/signextend_equivalence.py @@ -1,5 +1,6 @@ +from opcodes import SIGNEXTEND from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, Extract, SignExt, UGT """ Checking the implementation of SIGNEXTEND using Z3's native SignExt and Extract diff --git a/test/formal/signextend_shl.py b/test/formal/signextend_shl.py index 608b10eec..18b1baea1 100644 --- a/test/formal/signextend_shl.py +++ b/test/formal/signextend_shl.py @@ -1,5 +1,6 @@ +from opcodes import SHL, SIGNEXTEND from rule import Rule -from opcodes import * +from z3 import BitVec, LShR, ULE """ Rule: diff --git a/test/formal/signextend_shr.py b/test/formal/signextend_shr.py index 4364e6a23..a763314cd 100644 --- a/test/formal/signextend_shr.py +++ b/test/formal/signextend_shr.py @@ -1,5 +1,6 @@ +from opcodes import SIGNEXTEND, SAR, SHR from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal, ULE """ Rule: @@ -28,4 +29,3 @@ rule.check( SIGNEXTEND(A, SHR(B, X)), SAR(B, X) ) - diff --git a/test/formal/sub_not_zero_x_to_not_x_256.py b/test/formal/sub_not_zero_x_to_not_x_256.py index eb3301100..d8f1282ec 100644 --- a/test/formal/sub_not_zero_x_to_not_x_256.py +++ b/test/formal/sub_not_zero_x_to_not_x_256.py @@ -1,5 +1,6 @@ +from opcodes import NOT, SUB from rule import Rule -from opcodes import * +from z3 import BitVec, BitVecVal """ Rule: diff --git a/test/formal/sub_sub.py b/test/formal/sub_sub.py index d6099c91f..643941085 100644 --- a/test/formal/sub_sub.py +++ b/test/formal/sub_sub.py @@ -1,5 +1,6 @@ +from opcodes import ADD, SUB from rule import Rule -from opcodes import * +from z3 import BitVec """ Rules: diff --git a/test/formal/util.py b/test/formal/util.py index ec98f9c81..8d0debbef 100644 --- a/test/formal/util.py +++ b/test/formal/util.py @@ -1,27 +1,27 @@ -from z3 import * +from z3 import BitVecVal, Concat, If def BVUnsignedUpCast(x, n_bits): - assert(x.size() <= n_bits) + assert x.size() <= n_bits if x.size() < n_bits: return Concat(BitVecVal(0, n_bits - x.size()), x) else: return x def BVUnsignedMax(type_bits, n_bits): - assert(type_bits <= n_bits) + assert type_bits <= n_bits return BitVecVal((1 << type_bits) - 1, n_bits) def BVSignedUpCast(x, n_bits): - assert(x.size() <= n_bits) + assert x.size() <= n_bits if x.size() < n_bits: return Concat(If(x < 0, BitVecVal(-1, n_bits - x.size()), BitVecVal(0, n_bits - x.size())), x) else: return x def BVSignedMax(type_bits, n_bits): - assert(type_bits <= n_bits) + assert type_bits <= n_bits return BitVecVal((1 << (type_bits - 1)) - 1, n_bits) def BVSignedMin(type_bits, n_bits): - assert(type_bits <= n_bits) + assert type_bits <= n_bits return BitVecVal(-(1 << (type_bits - 1)), n_bits) diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 0c1e4dbad..c7f28f654 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -21,15 +21,16 @@ * Tests for the assembler. */ -#include #include +#include +#include #include +#include +#include #include #include -#include -#include using namespace std; using namespace solidity::langutil; @@ -165,6 +166,89 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) ); } +BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps) +{ + // Tests for 1, 2, 3 number of immutables. + for (int numImmutables = 1; numImmutables <= 3; ++numImmutables) + { + BOOST_TEST_MESSAGE("NumImmutables: "s + to_string(numImmutables)); + // Tests for the cases 1, 2, 3 occurrences of an immutable reference. + for (int numActualRefs = 1; numActualRefs <= 3; ++numActualRefs) + { + BOOST_TEST_MESSAGE("NumActualRefs: "s + to_string(numActualRefs)); + auto const NumExpectedMappings = + ( + 2 + // PUSH PUSH + (numActualRefs - 1) * 5 + // DUP DUP PUSH ADD MTOSRE + 3 // PUSH ADD MSTORkhbE + ) * numImmutables; + + auto constexpr NumSubs = 1; + auto constexpr NumOpcodesWithoutMappings = + NumSubs + // PUSH for every sub assembly + 1; // INVALID + + auto assemblyName = make_shared("root.asm"); + auto subName = make_shared("sub.asm"); + + map indices = { + { *assemblyName, 0 }, + { *subName, 1 } + }; + + auto subAsm = make_shared(); + for (char i = 0; i < numImmutables; ++i) + { + for (int r = 0; r < numActualRefs; ++r) + { + subAsm->setSourceLocation(SourceLocation{10*i, 10*i + 6 + r, subName}); + subAsm->appendImmutable(string(1, char('a' + i))); // "a", "b", ... + } + } + + Assembly assembly; + for (char i = 1; i <= numImmutables; ++i) + { + assembly.setSourceLocation({10*i, 10*i + 3+i, assemblyName}); + assembly.append(u256(0x71)); // immutble value + assembly.append(u256(0)); // target... modules? + assembly.appendImmutableAssignment(string(1, char('a' + i - 1))); + } + + assembly.appendSubroutine(subAsm); + + checkCompilation(assembly); + + string const sourceMappings = AssemblyItem::computeSourceMapping(assembly.items(), indices); + auto const numberOfMappings = std::count(sourceMappings.begin(), sourceMappings.end(), ';'); + + LinkerObject const& obj = assembly.assemble(); + string const disassembly = disassemble(obj.bytecode, "\n"); + auto const numberOfOpcodes = std::count(disassembly.begin(), disassembly.end(), '\n'); + + #if 0 // {{{ debug prints + { + LinkerObject const& subObj = assembly.sub(0).assemble(); + string const subDisassembly = disassemble(subObj.bytecode, "\n"); + cout << '\n'; + cout << "### immutables: " << numImmutables << ", refs: " << numActualRefs << '\n'; + cout << " - srcmap: \"" << sourceMappings << "\"\n"; + cout << " - src mappings: " << numberOfMappings << '\n'; + cout << " - opcodes: " << numberOfOpcodes << '\n'; + cout << " - subs: " << assembly.numSubs() << '\n'; + cout << " - sub opcodes " << std::count(subDisassembly.begin(), subDisassembly.end(), '\n') << '\n'; + cout << " - sub srcmaps " << AssemblyItem::computeSourceMapping(subAsm->items(), indices) << '\n'; + cout << " - main bytecode:\n\t" << disassemble(obj.bytecode, "\n\t"); + cout << "\r - sub bytecode:\n\t" << disassemble(subObj.bytecode, "\n\t"); + } + #endif // }}} + + BOOST_REQUIRE_EQUAL(NumExpectedMappings, numberOfMappings); + BOOST_REQUIRE_EQUAL(NumExpectedMappings, numberOfOpcodes - NumOpcodesWithoutMappings); + } + } +} + BOOST_AUTO_TEST_CASE(immutable) { map indices = { diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 0ec9b50a2..f0e5e455f 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -28,8 +28,9 @@ #include -#include +#include #include +#include #include #include @@ -59,7 +60,12 @@ std::optional parseAndReturnFirstError( AssemblyStack::Machine _machine = AssemblyStack::Machine::EVM ) { - AssemblyStack stack(solidity::test::CommonOptions::get().evmVersion(), _language, solidity::frontend::OptimiserSettings::none()); + AssemblyStack stack( + solidity::test::CommonOptions::get().evmVersion(), + _language, + solidity::frontend::OptimiserSettings::none(), + DebugInfoSelection::None() + ); bool success = false; try { @@ -125,7 +131,12 @@ Error expectError( void parsePrintCompare(string const& _source, bool _canWarn = false) { - AssemblyStack stack(solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::Assembly, OptimiserSettings::none()); + AssemblyStack stack( + solidity::test::CommonOptions::get().evmVersion(), + AssemblyStack::Language::Assembly, + OptimiserSettings::none(), + DebugInfoSelection::None() + ); BOOST_REQUIRE(stack.parseAndAnalyze("", _source)); if (_canWarn) BOOST_REQUIRE(!Error::containsErrors(stack.errors())); @@ -210,7 +221,12 @@ BOOST_AUTO_TEST_CASE(print_string_literal_unicode) { string source = "{ let x := \"\\u1bac\" }"; string parsed = "object \"object\" {\n code { let x := \"\\xe1\\xae\\xac\" }\n}\n"; - AssemblyStack stack(solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::Assembly, OptimiserSettings::none()); + AssemblyStack stack( + solidity::test::CommonOptions::get().evmVersion(), + AssemblyStack::Language::Assembly, + OptimiserSettings::none(), + DebugInfoSelection::None() + ); BOOST_REQUIRE(stack.parseAndAnalyze("", source)); BOOST_REQUIRE(stack.errors().empty()); BOOST_CHECK_EQUAL(stack.print(), parsed); diff --git a/test/libsolidity/SemVerMatcher.cpp b/test/libsolidity/SemVerMatcher.cpp index b0fbb8547..a69b2a39d 100644 --- a/test/libsolidity/SemVerMatcher.cpp +++ b/test/libsolidity/SemVerMatcher.cpp @@ -171,6 +171,8 @@ BOOST_AUTO_TEST_CASE(negative_range) { // Negative range tests vector> tests = { + {"^0^1", "0.0.0"}, + {"^0^1", "1.0.0"}, {"1.0.0 - 2.0.0", "2.2.3"}, {"1.0", "1.0.0-pre"}, {"1", "1.0.0-pre"}, diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index 349baf481..f3921613f 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -21,17 +21,22 @@ * Framework for executing Solidity contracts and testing them against C++ implementation. */ -#include -#include -#include #include + +#include #include #include +#include + +#include +#include + using namespace solidity; -using namespace solidity::test; using namespace solidity::frontend; using namespace solidity::frontend::test; +using namespace solidity::langutil; +using namespace solidity::test; using namespace std; bytes SolidityExecutionFramework::multiSourceCompileContract( @@ -91,8 +96,12 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( else if (forceEnableOptimizer) optimiserSettings = OptimiserSettings::full(); - yul::AssemblyStack - asmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, optimiserSettings); + yul::AssemblyStack asmStack( + m_evmVersion, + yul::AssemblyStack::Language::StrictAssembly, + optimiserSettings, + DebugInfoSelection::All() + ); bool analysisSuccessful = asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName)); solAssert(analysisSuccessful, "Code that passed analysis in CompilerStack can't have errors"); diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index ee1bf0239..5f7b8d472 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -112,9 +112,14 @@ bytes compileFirstExpression( if (!sourceUnit) return bytes(); } - catch(boost::exception const& _e) + catch (boost::exception const& _e) { - auto msg = std::string("Parsing source code failed with: \n") + boost::diagnostic_information(_e); + string msg = "Parsing source code failed with:\n" + boost::diagnostic_information(_e); + BOOST_FAIL(msg); + } + catch (...) + { + string msg = "Parsing source code failed with:\n" + boost::current_exception_diagnostic_information(); BOOST_FAIL(msg); } diff --git a/test/libsolidity/semanticTests/types/mapping/user_defined_types_mapping_storage.sol b/test/libsolidity/semanticTests/types/mapping/user_defined_types_mapping_storage.sol new file mode 100644 index 000000000..ae6756822 --- /dev/null +++ b/test/libsolidity/semanticTests/types/mapping/user_defined_types_mapping_storage.sol @@ -0,0 +1,28 @@ +type A is uint; +type B is uint; + +library L { + function f(mapping(A=>B) storage _m, B _v) public { _m[A.wrap(uint(2))] = _v; } + function f(mapping(uint=>uint) storage _m, uint _v) public { _m[uint(3)] = _v; } +} + +contract C { + mapping(uint=>uint) uintMap; + mapping(A=>B) abMap; + + function testAB() public returns (bool) { + L.f(abMap, B.wrap(3)); + return B.unwrap(abMap[A.wrap(uint(2))]) == 3; + } + function testUint() public returns (bool) { + L.f(uintMap, 4); + return uintMap[3] == 4; + } +} + +// ==== +// compileViaYul: also +// ---- +// library: L +// testAB() -> true +// testUint() -> true diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_6.sol b/test/libsolidity/syntaxTests/pragma/broken_version_6.sol new file mode 100644 index 000000000..ab98e4f2a --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_6.sol @@ -0,0 +1,3 @@ +pragma solidity v1.2.3; +// ---- +// ParserError 1684: (0-23): Found version pragma, but failed to parse it. Please ensure there is a trailing semicolon. diff --git a/test/libsolidity/syntaxTests/pragma/broken_version_7.sol b/test/libsolidity/syntaxTests/pragma/broken_version_7.sol new file mode 100644 index 000000000..b4b6fea7a --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/broken_version_7.sol @@ -0,0 +1,3 @@ +pragma solidity >0.5.0<; +// ---- +// ParserError 1684: (0-24): Found version pragma, but failed to parse it. Please ensure there is a trailing semicolon. diff --git a/test/libsolidity/syntaxTests/pragma/version_range.sol b/test/libsolidity/syntaxTests/pragma/version_range.sol new file mode 100644 index 000000000..4d6cdf6b9 --- /dev/null +++ b/test/libsolidity/syntaxTests/pragma/version_range.sol @@ -0,0 +1,2 @@ +pragma solidity >=0.4.0 <0.9.0; +// ---- diff --git a/test/libsolidity/syntaxTests/types/mapping/int_mapping.sol b/test/libsolidity/syntaxTests/types/mapping/int_mapping.sol new file mode 100644 index 000000000..c041271e1 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/mapping/int_mapping.sol @@ -0,0 +1,5 @@ +library L { + function f(mapping(uint=>uint) memory) public {} +} +// ---- +// TypeError 4061: (25-51): Type mapping(uint256 => uint256) is only valid in storage because it contains a (nested) mapping. diff --git a/test/libsolidity/syntaxTests/types/mapping/user_defined_types_mapping_memory.sol b/test/libsolidity/syntaxTests/types/mapping/user_defined_types_mapping_memory.sol new file mode 100644 index 000000000..51b3c0388 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/mapping/user_defined_types_mapping_memory.sol @@ -0,0 +1,6 @@ +type T is uint; +library L { + function f(mapping(T=>T) memory) public {} +} +// ---- +// TypeError 4061: (41-61): Type mapping(T => T) is only valid in storage because it contains a (nested) mapping. diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 8099037f3..fc9be2001 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -23,8 +23,6 @@ #include -#include - #include #include #include @@ -33,8 +31,10 @@ #include #include -#include +#include #include +#include +#include #include @@ -60,7 +60,8 @@ pair, shared_ptr> yul::test::parse(strin _yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly, solidity::test::CommonOptions::get().optimize ? solidity::frontend::OptimiserSettings::standard() : - solidity::frontend::OptimiserSettings::minimal() + solidity::frontend::OptimiserSettings::minimal(), + DebugInfoSelection::All() ); if (!stack.parseAndAnalyze("", _source) || !stack.errors().empty()) BOOST_FAIL("Invalid source."); diff --git a/test/libyul/ControlFlowSideEffectsTest.cpp b/test/libyul/ControlFlowSideEffectsTest.cpp new file mode 100644 index 000000000..aff3c564d --- /dev/null +++ b/test/libyul/ControlFlowSideEffectsTest.cpp @@ -0,0 +1,79 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::yul; +using namespace solidity::yul::test; +using namespace solidity::frontend::test; + +namespace +{ +string toString(ControlFlowSideEffects const& _sideEffects) +{ + vector r; + if (_sideEffects.canTerminate) + r.emplace_back("can terminate"); + if (_sideEffects.canRevert) + r.emplace_back("can revert"); + if (_sideEffects.canContinue) + r.emplace_back("can continue"); + return util::joinHumanReadable(r); +} +} + +ControlFlowSideEffectsTest::ControlFlowSideEffectsTest(string const& _filename): + TestCase(_filename) +{ + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); +} + +TestCase::TestResult ControlFlowSideEffectsTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) +{ + Object obj; + std::tie(obj.code, obj.analysisInfo) = yul::test::parse(m_source, false); + if (!obj.code) + BOOST_THROW_EXCEPTION(runtime_error("Parsing input failed.")); + + std::map sideEffects = + ControlFlowSideEffectsCollector( + EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), + *obj.code + ).functionSideEffects(); + + std::map controlFlowSideEffectsStr; + for (auto&& [fun, effects]: sideEffects) + controlFlowSideEffectsStr[fun.str()] = toString(effects); + + m_obtainedResult.clear(); + for (auto&& [functionName, effect]: controlFlowSideEffectsStr) + m_obtainedResult += functionName + (effect.empty() ? ":" : ": " + effect) + "\n"; + + return checkResult(_stream, _linePrefix, _formatted); +} diff --git a/test/libyul/ControlFlowSideEffectsTest.h b/test/libyul/ControlFlowSideEffectsTest.h new file mode 100644 index 000000000..f91378e55 --- /dev/null +++ b/test/libyul/ControlFlowSideEffectsTest.h @@ -0,0 +1,40 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +#include +#include +#include +#include + +namespace solidity::yul::test +{ + +class ControlFlowSideEffectsTest: public solidity::frontend::test::TestCase +{ +public: + static std::unique_ptr create(Config const& _config) + { return std::make_unique(_config.filename); } + explicit ControlFlowSideEffectsTest(std::string const& _filename); + TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; +}; + +} diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index 043eae331..38ef5ad39 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -47,7 +47,12 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _ solidity::frontend::OptimiserSettings settings = solidity::frontend::OptimiserSettings::none(); settings.runYulOptimiser = false; settings.optimizeStackAllocation = m_stackOpt; - AssemblyStack stack(EVMVersion{}, AssemblyStack::Language::StrictAssembly, settings); + AssemblyStack stack( + EVMVersion{}, + AssemblyStack::Language::StrictAssembly, + settings, + DebugInfoSelection::All() + ); if (!stack.parseAndAnalyze("", m_source)) { AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; diff --git a/test/libyul/EwasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp index 6051c2e20..9bd80f4b1 100644 --- a/test/libyul/EwasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -82,7 +83,8 @@ bool EwasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bo m_stack = AssemblyStack( solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::none() + solidity::frontend::OptimiserSettings::none(), + DebugInfoSelection::All() ); if (m_stack.parseAndAnalyze("", m_source)) { diff --git a/test/libyul/Inliner.cpp b/test/libyul/Inliner.cpp index f80ec433e..75ae064e5 100644 --- a/test/libyul/Inliner.cpp +++ b/test/libyul/Inliner.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index 37b1688a9..256bced21 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -26,6 +26,7 @@ #include +#include #include #include @@ -64,7 +65,8 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li AssemblyStack stack( EVMVersion(), m_wasm ? AssemblyStack::Language::Ewasm : AssemblyStack::Language::StrictAssembly, - OptimiserSettings::preset(m_optimisationPreset) + OptimiserSettings::preset(m_optimisationPreset), + DebugInfoSelection::All() ); if (!stack.parseAndAnalyze("source", m_source)) { diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index d70d2002c..1d6f0bed3 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -23,6 +23,7 @@ #include +#include #include #include @@ -60,7 +61,8 @@ pair parse(string const& _source) AssemblyStack asmStack( solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::none() + solidity::frontend::OptimiserSettings::none(), + DebugInfoSelection::All() ); bool success = asmStack.parseAndAnalyze("source", _source); return {success, asmStack.errors()}; @@ -181,7 +183,8 @@ BOOST_AUTO_TEST_CASE(to_string) AssemblyStack asmStack( solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::none() + solidity::frontend::OptimiserSettings::none(), + DebugInfoSelection::All() ); BOOST_REQUIRE(asmStack.parseAndAnalyze("source", code)); BOOST_CHECK_EQUAL(asmStack.print(), expectation); diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index 6f7da9f98..ba47b4c08 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -67,7 +68,8 @@ bool YulInterpreterTest::parse(ostream& _stream, string const& _linePrefix, bool AssemblyStack stack( solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::none() + solidity::frontend::OptimiserSettings::none(), + DebugInfoSelection::All() ); if (stack.parseAndAnalyze("", m_source)) { diff --git a/test/libyul/YulOptimizerTestCommon.cpp b/test/libyul/YulOptimizerTestCommon.cpp index 00aba3c79..962cb18a4 100644 --- a/test/libyul/YulOptimizerTestCommon.cpp +++ b/test/libyul/YulOptimizerTestCommon.cpp @@ -61,7 +61,6 @@ #include #include #include -#include #include #include diff --git a/test/libyul/controlFlowSideEffects/eval_order.yul b/test/libyul/controlFlowSideEffects/eval_order.yul new file mode 100644 index 000000000..a207d7a19 --- /dev/null +++ b/test/libyul/controlFlowSideEffects/eval_order.yul @@ -0,0 +1,19 @@ +{ + function a() -> x { + revert(0, 0) + } + function b() -> x { + return(0, 0) + } + function c() { + sstore(a(), b()) + } + function d() { + sstore(b(), a()) + } +} +// ---- +// a: can revert +// b: can terminate +// c: can terminate +// d: can revert diff --git a/test/libyul/controlFlowSideEffects/for_loop.yul b/test/libyul/controlFlowSideEffects/for_loop.yul new file mode 100644 index 000000000..1f3714a48 --- /dev/null +++ b/test/libyul/controlFlowSideEffects/for_loop.yul @@ -0,0 +1,55 @@ +{ + function a() { + for { leave } calldataload(0) { } { + break + revert(0, 0) + } + } + function b() { + for { } calldataload(0) { leave } { + break + revert(0, 0) + } + } + function b2() { + for { } calldataload(0) { leave } { + revert(0, 0) + } + } + function c() { + for { } calldataload(0) { revert(0, 0) } { + break + } + } + function c2() { + for { } calldataload(0) { revert(0, 0) } { + break + revert(0, 0) + } + } + function d() { + for { } calldataload(0) { revert(0, 0) } { + continue + } + } + function e() { + for { } calldataload(0) { revert(0, 0) } { + if calldataload(1) { break } + } + } + function f() { + for { } calldataload(0) { } { + if calldataload(1) { continue } + revert(0, 0) + } + } +} +// ---- +// a: can continue +// b: can continue +// b2: can revert, can continue +// c: can continue +// c2: can continue +// d: can revert, can continue +// e: can revert, can continue +// f: can revert, can continue diff --git a/test/libyul/controlFlowSideEffects/leave.yul b/test/libyul/controlFlowSideEffects/leave.yul new file mode 100644 index 000000000..bbc977820 --- /dev/null +++ b/test/libyul/controlFlowSideEffects/leave.yul @@ -0,0 +1,13 @@ +{ + function a() { + revert(0, 0) + leave + } + function b() { + leave + revert(0, 0) + } +} +// ---- +// a: can revert +// b: can continue diff --git a/test/libyul/controlFlowSideEffects/recursion.yul b/test/libyul/controlFlowSideEffects/recursion.yul new file mode 100644 index 000000000..c4176d502 --- /dev/null +++ b/test/libyul/controlFlowSideEffects/recursion.yul @@ -0,0 +1,37 @@ +{ + function a() { + if calldataload(0) { + revert(0, 0) + } + reg() + b() + } + function b() { + a() + return(0, 0) + } + function c() { + c() + revert(0, 0) + } + function d() { + switch calldataload(0) + case 0 { x() } + case 1 { y() reg() revert(0, 0) } + default { z() } + } + function x() { d() revert(0, 0) } + function y() { reg() x() } + function z() { y() } + + function reg() {} +} +// ---- +// a: can revert +// b: can revert +// c: +// d: +// reg: can continue +// x: +// y: +// z: diff --git a/test/libyul/controlFlowSideEffects/simple_conditionals.yul b/test/libyul/controlFlowSideEffects/simple_conditionals.yul new file mode 100644 index 000000000..ec15193df --- /dev/null +++ b/test/libyul/controlFlowSideEffects/simple_conditionals.yul @@ -0,0 +1,34 @@ +{ + function a() { + if calldataload(0) { g() } + } + function b() { + g() + if calldataload(0) { } + } + function c() { + if calldataload(0) { } + g() + } + function d() { + stop() + if calldataload(0) { g() } + } + function e() { + if calldataload(0) { g() } + stop() + } + function f() { + g() + if calldataload(0) { g() } + } + function g() { revert(0, 0) } +} +// ---- +// a: can revert, can continue +// b: can revert +// c: can revert +// d: can terminate +// e: can terminate, can revert +// f: can revert +// g: can revert diff --git a/test/libyul/controlFlowSideEffects/simple_functions.yul b/test/libyul/controlFlowSideEffects/simple_functions.yul new file mode 100644 index 000000000..b6b14d39d --- /dev/null +++ b/test/libyul/controlFlowSideEffects/simple_functions.yul @@ -0,0 +1,17 @@ +{ + function a() {} + function f() { g() } + function g() { revert(0, 0) } + function h() { stop() } + function i() { h() } + function j() { h() g() } + function k() { g() h() } +} +// ---- +// a: can continue +// f: can revert +// g: can revert +// h: can terminate +// i: can terminate +// j: can terminate +// k: can revert diff --git a/test/libyul/controlFlowSideEffects/switch.yul b/test/libyul/controlFlowSideEffects/switch.yul new file mode 100644 index 000000000..63b45ce30 --- /dev/null +++ b/test/libyul/controlFlowSideEffects/switch.yul @@ -0,0 +1,41 @@ +{ + function a() { + switch calldataload(0) + case 0 { revert(0, 0) } + } + function b() { + switch calldataload(0) + case 0 { revert(0, 0) } + default { revert(0, 0) } + } + function c() { + return(0, 0) + switch calldataload(0) + case 0 { revert(0, 0) } + default { } + } + function d() { + switch calldataload(0) + case 0 { return(0, 0) } + default { return(0, 0) } + revert(0, 0) + } + function e() { + switch calldataload(0) + case 0 { return(0, 0) } + revert(0, 0) + } + function f() { + switch calldataload(0) + case 0 { leave } + default { leave } + revert(0, 0) + } +} +// ---- +// a: can revert, can continue +// b: can revert +// c: can terminate +// d: can terminate +// e: can terminate, can revert +// f: can continue diff --git a/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul b/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul index a208d15a5..dcc41e7a0 100644 --- a/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul +++ b/test/libyul/objectCompiler/immutable_long_name_does_not_end_up_in_bytecode.yul @@ -17,4 +17,4 @@ object "a" { // assignImmutable("0x85a5b1db611c82c46f5fa18e39ae218397536256c451e5de155a86de843a9ad6") // Bytecode: 73123456789012345678901234567890123456789060005050 // Opcodes: PUSH20 0x1234567890123456789012345678901234567890 PUSH1 0x0 POP POP -// SourceMappings: 167:42:0:-:0;58:1;32:187 +// SourceMappings: 167:42:0:-:0;58:1;32:187; diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index 4f1a6f35d..41b77c115 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -15,6 +15,8 @@ if sub(2,1) { for { switch mul(1,2) case 2 { mstore(0x40, 0x20) } } sub(1,1) {} { mstore(0x80, 0x40) } } + sstore(0, array_index_access(x, 3)) + sstore(1, mload(0x40)) } // ---- // step: fullSuite @@ -24,7 +26,10 @@ // let p := mload(0x40) // mstore(0x40, add(p, 0x20)) // mstore(0x40, add(p, 96)) -// mstore(add(p, 128), 2) +// let p_1 := add(p, 128) +// mstore(p_1, 2) // mstore(0x40, 0x20) +// sstore(0, p_1) +// sstore(1, 0x20) // } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul index 6e217ae4f..93f2f4ad6 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul @@ -6,10 +6,10 @@ function foo() -> x_9 { x_9 := sub(1,sub(x_9,1)) - mstore(sub(1,div(sub(x_9,1),sub(1,sub(x_9,1)))), 1) + sstore(sub(1,div(sub(x_9,1),sub(1,sub(x_9,1)))), 1) } } // ---- // step: fullSuite // -// { { mstore(1, 1) } } +// { { sstore(1, 1) } } diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul index 427c9166b..a7ecc0e46 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul @@ -29,7 +29,7 @@ a,b := abi_decode_t_bytes_calldata_ptr(a,b) a,b := abi_decode_t_bytes_calldata_ptr(a,b) a,b := abi_decode_t_bytes_calldata_ptr(a,b) - mstore(a,b) + sstore(a,b) } // ---- // step: fullSuite @@ -43,7 +43,7 @@ // let a_4, b_4 := abi_decode_bytes_calldata(a_3, b_3) // let a_5, b_5 := abi_decode_bytes_calldata(a_4, b_4) // let a_6, b_6 := abi_decode_bytes_calldata(a_5, b_5) -// mstore(a_6, b_6) +// sstore(a_6, b_6) // } // function abi_decode_bytes_calldata(offset, end) -> arrayPos, length // { diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul index 4421dd3cd..3a061155b 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul @@ -7,7 +7,7 @@ a := mload(b) b := mload(a) } - mstore(a, b) + sstore(a, b) } // ---- // step: fullSuite @@ -21,6 +21,6 @@ // a := mload(mload(mload(b))) // b := mload(a) // } -// mstore(a, b) +// sstore(a, b) // } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul index 65c7512d3..1ed995124 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul @@ -1,5 +1,5 @@ { - mstore(f(1), 0) + sstore(f(1), 0) function f(x) -> y { switch x case 0 { y := 8 } @@ -9,4 +9,4 @@ // ---- // step: fullSuite // -// { { mstore(9, 0) } } +// { { sstore(9, 0) } } diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul index cff8bd755..6ca3314ab 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul @@ -1,5 +1,5 @@ { - mstore(f(3), 0) + sstore(f(3), 0) function f(x) -> y { switch x case 0 { y := 8 } @@ -10,4 +10,4 @@ // ---- // step: fullSuite // -// { { mstore(10, 0) } } +// { { sstore(10, 0) } } diff --git a/test/libyul/yulSyntaxTests/invalid_type4.yul b/test/libyul/yulSyntaxTests/invalid_type4.yul index 0c588a831..8195fcf90 100644 --- a/test/libyul/yulSyntaxTests/invalid_type4.yul +++ b/test/libyul/yulSyntaxTests/invalid_type4.yul @@ -5,5 +5,5 @@ // ==== // dialect: evmTyped // ---- -// TypeError 3781: (24-38): Expected a value of type "u256" but got "invalidType" +// TypeError 3781: (24-38): Expected a value of type "u256" but got "invalidType". // TypeError 5473: (24-38): "invalidType" is not a valid type (user defined types are not yet supported). diff --git a/test/libyul/yulSyntaxTests/type_check_cases_fail.yul b/test/libyul/yulSyntaxTests/type_check_cases_fail.yul index 1b3f779d1..d9b4c0204 100644 --- a/test/libyul/yulSyntaxTests/type_check_cases_fail.yul +++ b/test/libyul/yulSyntaxTests/type_check_cases_fail.yul @@ -6,5 +6,5 @@ // ==== // dialect: ewasm // ---- -// TypeError 3781: (28-33): Expected a value of type "i32" but got "i64" -// TypeError 3781: (46-51): Expected a value of type "i32" but got "i64" +// TypeError 3781: (28-33): Expected a value of type "i32" but got "i64". +// TypeError 3781: (46-51): Expected a value of type "i32" but got "i64". diff --git a/test/libyul/yulSyntaxTests/type_check_cases_fail_evmtyped.yul b/test/libyul/yulSyntaxTests/type_check_cases_fail_evmtyped.yul index 458372fe9..35926ccb2 100644 --- a/test/libyul/yulSyntaxTests/type_check_cases_fail_evmtyped.yul +++ b/test/libyul/yulSyntaxTests/type_check_cases_fail_evmtyped.yul @@ -6,5 +6,5 @@ // ==== // dialect: evmTyped // ---- -// TypeError 3781: (24-33): Expected a value of type "u256" but got "bool" -// TypeError 3781: (46-55): Expected a value of type "u256" but got "bool" +// TypeError 3781: (24-33): Expected a value of type "u256" but got "bool". +// TypeError 3781: (46-55): Expected a value of type "u256" but got "bool". diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 7b1dd375b..f2e4ea387 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -127,6 +127,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options) "--evm-version=spuriousDragon", "--experimental-via-ir", "--revert-strings=strip", + "--debug-info=location", "--pretty-json", "--json-indent=7", "--no-color", @@ -180,6 +181,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options) expectedOptions.output.evmVersion = EVMVersion::spuriousDragon(); expectedOptions.output.experimentalViaIR = true; expectedOptions.output.revertStrings = RevertStrings::Strip; + expectedOptions.output.debugInfoSelection = DebugInfoSelection::fromString("location"); expectedOptions.formatting.json = JsonFormat{JsonFormat::Pretty, 7}; expectedOptions.linker.libraries = { {"dir1/file1.sol:L", h160("1234567890123456789012345678901234567890")}, @@ -269,6 +271,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) "--overwrite", "--evm-version=spuriousDragon", "--revert-strings=strip", // Accepted but has no effect in assembly mode + "--debug-info=location", "--pretty-json", "--json-indent=1", "--no-color", @@ -289,10 +292,6 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) "underflow," "divByZero", "--model-checker-timeout=5", // Ignored in assembly mode - - // Accepted but has no effect in assembly mode - "--ast-compact-json", "--asm", "--asm-json", "--opcodes", "--bin", "--bin-runtime", "--abi", - "--ir", "--ir-optimized", "--ewasm", "--hashes", "--userdoc", "--devdoc", "--metadata", "--storage-layout", }; commandLine += assemblyOptions; if (expectedLanguage == AssemblyStack::Language::StrictAssembly || expectedLanguage == AssemblyStack::Language::Ewasm) @@ -319,6 +318,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) expectedOptions.output.overwriteFiles = true; expectedOptions.output.evmVersion = EVMVersion::spuriousDragon(); expectedOptions.output.revertStrings = RevertStrings::Strip; + expectedOptions.output.debugInfoSelection = DebugInfoSelection::fromString("location"); expectedOptions.formatting.json = JsonFormat {JsonFormat::Pretty, 1}; expectedOptions.assembly.targetMachine = expectedMachine; expectedOptions.assembly.inputLanguage = expectedLanguage; @@ -328,11 +328,6 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) }; expectedOptions.formatting.coloredOutput = false; expectedOptions.formatting.withErrorIds = true; - expectedOptions.compiler.outputs = { - true, true, true, true, true, - true, true, true, true, true, - true, true, true, true, true, - }; if (expectedLanguage == AssemblyStack::Language::StrictAssembly || expectedLanguage == AssemblyStack::Language::Ewasm) { expectedOptions.optimizer.enabled = true; @@ -388,10 +383,6 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options) "underflow," "divByZero", "--model-checker-timeout=5", // Ignored in Standard JSON mode - - // Accepted but has no effect in Standard JSON mode - "--ast-compact-json", "--asm", "--asm-json", "--opcodes", "--bin", "--bin-runtime", "--abi", - "--ir", "--ir-optimized", "--ewasm", "--hashes", "--userdoc", "--devdoc", "--metadata", "--storage-layout", }; CommandLineOptions expectedOptions; @@ -408,11 +399,6 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options) expectedOptions.formatting.json = JsonFormat {JsonFormat::Pretty, 1}; expectedOptions.formatting.coloredOutput = false; expectedOptions.formatting.withErrorIds = true; - expectedOptions.compiler.outputs = { - true, true, true, true, true, - true, true, true, true, true, - true, true, true, true, true, - }; expectedOptions.compiler.estimateGas = true; expectedOptions.compiler.combinedJsonRequests = CombinedJsonRequests{}; expectedOptions.compiler.combinedJsonRequests->abi = true; diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 18b04afe8..18e3d4377 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable(isoltest ../libsolidity/SMTCheckerTest.cpp ../libyul/Common.cpp ../libyul/ControlFlowGraphTest.cpp + ../libyul/ControlFlowSideEffectsTest.cpp ../libyul/EVMCodeTransformTest.cpp ../libyul/EwasmTranslationTest.cpp ../libyul/FunctionSideEffects.cpp diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 73adbc62b..5ae1a3f99 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -201,15 +201,13 @@ TestTool::Result TestTool::process() catch (std::exception const& _e) { AnsiColorized(cout, formatted, {BOLD, RED}) << - "Exception during test" << - (_e.what() ? ": " + string(_e.what()) : ".") << - endl; + "Exception during test: " << boost::diagnostic_information(_e) << endl; return Result::Exception; } catch (...) { AnsiColorized(cout, formatted, {BOLD, RED}) << - "Unknown exception during test." << endl; + "Unknown exception during test: " << boost::current_exception_diagnostic_information() << endl; return Result::Exception; } } diff --git a/test/tools/ossfuzz/YulEvmoneInterface.h b/test/tools/ossfuzz/YulEvmoneInterface.h index b7a430b60..0b3384940 100644 --- a/test/tools/ossfuzz/YulEvmoneInterface.h +++ b/test/tools/ossfuzz/YulEvmoneInterface.h @@ -23,6 +23,8 @@ #include +#include + namespace solidity::test::fuzzer { class YulAssembler @@ -36,7 +38,8 @@ public: m_stack( _version, solidity::yul::AssemblyStack::Language::StrictAssembly, - _optSettings + _optSettings, + langutil::DebugInfoSelection::All() ), m_yulProgram(_yulSource), m_optimiseYul(_optSettings.runYulOptimiser) diff --git a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp index e25de4f05..7142ec23c 100644 --- a/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_assembly_ossfuzz.cpp @@ -17,9 +17,11 @@ // SPDX-License-Identifier: GPL-3.0 #include -#include #include +#include +#include + using namespace solidity; using namespace solidity::yul; using namespace std; @@ -38,7 +40,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) AssemblyStack stack( langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::full() + solidity::frontend::OptimiserSettings::full(), + langutil::DebugInfoSelection::All() ); if (!stack.parseAndAnalyze("source", input)) diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index 6c7bc61cb..a3a789bc9 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -61,7 +62,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) AssemblyStack stack( langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::full() + solidity::frontend::OptimiserSettings::full(), + DebugInfoSelection::All() ); try { diff --git a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp index b1aa9a21f..05a0179bf 100644 --- a/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_opt_ossfuzz.cpp @@ -17,9 +17,12 @@ // SPDX-License-Identifier: GPL-3.0 #include + +#include #include using namespace solidity; +using namespace solidity::langutil; using namespace solidity::util; using namespace solidity::yul; using namespace std; @@ -38,7 +41,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) AssemblyStack stack( langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::full() + solidity::frontend::OptimiserSettings::full(), + DebugInfoSelection::All() ); if (!stack.parseAndAnalyze("source", input)) diff --git a/test/tools/ossfuzz/yulProtoFuzzer.cpp b/test/tools/ossfuzz/yulProtoFuzzer.cpp index 7118a0596..ca15b3769 100644 --- a/test/tools/ossfuzz/yulProtoFuzzer.cpp +++ b/test/tools/ossfuzz/yulProtoFuzzer.cpp @@ -30,15 +30,16 @@ #include +#include #include #include using namespace solidity; +using namespace solidity::langutil; using namespace solidity::yul; using namespace solidity::yul::test; using namespace solidity::yul::test::yul_fuzzer; -using namespace solidity::langutil; using namespace std; DEFINE_PROTO_FUZZER(Program const& _input) @@ -64,7 +65,8 @@ DEFINE_PROTO_FUZZER(Program const& _input) AssemblyStack stack( version, AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::full() + solidity::frontend::OptimiserSettings::full(), + DebugInfoSelection::All() ); // Parse protobuf mutated YUL code diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index abb0df82f..22f67e1cf 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -63,7 +64,8 @@ DEFINE_PROTO_FUZZER(Program const& _input) AssemblyStack stack( version, AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::full() + solidity::frontend::OptimiserSettings::full(), + DebugInfoSelection::All() ); // Parse protobuf mutated YUL code diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index 7906be744..cb90a3f43 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -58,7 +59,8 @@ pair, shared_ptr> parse(string const& _source AssemblyStack stack( langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::none() + solidity::frontend::OptimiserSettings::none(), + DebugInfoSelection::Default() ); if (stack.parseAndAnalyze("--INPUT--", _source)) { diff --git a/tools/solidityUpgrade/SourceUpgrade.cpp b/tools/solidityUpgrade/SourceUpgrade.cpp index 85dca2297..7c70b1d16 100644 --- a/tools/solidityUpgrade/SourceUpgrade.cpp +++ b/tools/solidityUpgrade/SourceUpgrade.cpp @@ -306,13 +306,13 @@ void SourceUpgrade::tryCompile() const { error() << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl; } - catch (std::exception const& _e) + catch (std::exception const& _exception) { - error() << (_e.what() ? ": " + string(_e.what()) : ".") << endl; + error() << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl; } catch (...) { - error() << "Unknown exception during compilation." << endl; + error() << "Unknown exception during compilation: " << boost::current_exception_diagnostic_information() << endl; } } @@ -517,7 +517,7 @@ ReadCallback::Callback SourceUpgrade::fileReader() } catch (...) { - return ReadCallback::Result{false, "Unknown exception in read callback."}; + return ReadCallback::Result{false, "Unknown exception in read callback: " + boost::current_exception_diagnostic_information()}; } }; @@ -533,7 +533,7 @@ void SourceUpgrade::resetCompiler() void SourceUpgrade::resetCompiler(ReadCallback::Callback const& _callback) { - m_compiler.reset(new CompilerStack(_callback)); + m_compiler = std::make_unique(_callback); m_compiler->setSources(m_sourceCodes); m_compiler->setParserErrorRecovery(true); } diff --git a/tools/solidityUpgrade/SourceUpgrade.h b/tools/solidityUpgrade/SourceUpgrade.h index 11e7e12a9..f3b5d3572 100644 --- a/tools/solidityUpgrade/SourceUpgrade.h +++ b/tools/solidityUpgrade/SourceUpgrade.h @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/tools/solidityUpgrade/main.cpp b/tools/solidityUpgrade/main.cpp index 11026884a..55ed0118c 100644 --- a/tools/solidityUpgrade/main.cpp +++ b/tools/solidityUpgrade/main.cpp @@ -86,6 +86,10 @@ int main(int argc, char** argv) { cerr << "Exception while processing input: " << boost::diagnostic_information(_exception) << endl; } + catch (...) + { + cerr << "Unknown exception while processing input: " << boost::current_exception_diagnostic_information() << endl; + } return 0; }