diff --git a/.circleci/README.md b/.circleci/README.md index b48adba24ca5..338e858d9c82 100644 --- a/.circleci/README.md +++ b/.circleci/README.md @@ -7,15 +7,15 @@ The docker images are build locally on the developer machine: ```sh cd .circleci/docker/ -docker build -t ethereum/solidity-buildpack-deps:ubuntu1904- -f Dockerfile.ubuntu1904 . -docker push ethereum/solidity-buildpack-deps:ubuntu1904- +docker build -t ethereum/solidity-buildpack-deps:ubuntu2004- -f Dockerfile.ubuntu2004 . +docker push ethereum/solidity-buildpack-deps:ubuntu2004- ``` -The current revisions per docker image are stored in [circle ci pipeline parameters](https://github.com/CircleCI-Public/api-preview-docs/blob/master/docs/pipeline-parameters.md#pipeline-parameters) called `-docker-image-rev` (e.g., `ubuntu-1904-docker-image-rev`). Please update the value assigned to the parameter(s) corresponding to the docker image(s) being updated at the time of the update. Please verify that the value assigned to the parameter matches the revision part of the docker image tag (`` in the docker build/push snippet shown above). Otherwise, the docker image used by circle ci and the one actually pushed to docker hub will differ. +The current revisions per docker image are stored in [circle ci pipeline parameters](https://github.com/CircleCI-Public/api-preview-docs/blob/master/docs/pipeline-parameters.md#pipeline-parameters) called `-docker-image-rev` (e.g., `ubuntu-2004-docker-image-rev`). Please update the value assigned to the parameter(s) corresponding to the docker image(s) being updated at the time of the update. Please verify that the value assigned to the parameter matches the revision part of the docker image tag (`` in the docker build/push snippet shown above). Otherwise, the docker image used by circle ci and the one actually pushed to docker hub will differ. Once the docker image has been built and pushed to Dockerhub, you can find it at: - https://hub.docker.com/r/ethereum/solidity-buildpack-deps:ubuntu1904- + https://hub.docker.com/r/ethereum/solidity-buildpack-deps:ubuntu2004- where the image tag reflects the target OS and revision to build Solidity and run its tests on. @@ -24,7 +24,7 @@ where the image tag reflects the target OS and revision to build Solidity and ru ```sh cd solidity # Mounts your local solidity directory in docker container for testing -docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu1904- /bin/bash +docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu2004- /bin/bash cd /src/solidity ``` diff --git a/.circleci/config.yml b/.circleci/config.yml index 063e11bb5fc8..49f78fa19b11 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,12 +10,12 @@ parameters: ubuntu-1804-docker-image-rev: type: string default: "4" - ubuntu-1904-docker-image-rev: + ubuntu-2004-docker-image-rev: type: string - default: "4" - ubuntu-1904-clang-docker-image-rev: + default: "1" + ubuntu-2004-clang-docker-image-rev: type: string - default: "5" + default: "1" ubuntu-1604-clang-ossfuzz-docker-image-rev: type: string default: "2" @@ -50,6 +50,7 @@ defaults: cd build protoc --proto_path=../test/tools/ossfuzz yulProto.proto --cpp_out=../test/tools/ossfuzz protoc --proto_path=../test/tools/ossfuzz abiV2Proto.proto --cpp_out=../test/tools/ossfuzz + protoc --proto_path=../test/tools/ossfuzz solProto.proto --cpp_out=../test/tools/ossfuzz cmake .. -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-Release} $CMAKE_OPTIONS make ossfuzz ossfuzz_proto ossfuzz_abiv2 -j4 @@ -97,6 +98,7 @@ defaults: - test/tools/ossfuzz/strictasm_opt_ossfuzz - test/tools/ossfuzz/yul_proto_diff_ossfuzz - test/tools/ossfuzz/yul_proto_ossfuzz + - test/tools/ossfuzz/sol_proto_ossfuzz # test result output directory - artifacts_test_results: &artifacts_test_results @@ -137,9 +139,9 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - test_ubuntu1904_clang: &test_ubuntu1904_clang + - test_ubuntu2004_clang: &test_ubuntu2004_clang docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-<< pipeline.parameters.ubuntu-1904-clang-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-clang-<< pipeline.parameters.ubuntu-2004-clang-docker-image-rev >> steps: - checkout - attach_workspace: @@ -148,9 +150,9 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - test_ubuntu1904: &test_ubuntu1904 + - test_ubuntu2004: &test_ubuntu2004 docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> steps: - checkout - attach_workspace: @@ -160,7 +162,7 @@ defaults: - store_artifacts: *artifacts_test_results - test_asan: &test_asan - <<: *test_ubuntu1904 + <<: *test_ubuntu2004 steps: - checkout - attach_workspace: @@ -179,7 +181,7 @@ defaults: tags: only: /.*/ - - workflow_ubuntu1904: &workflow_ubuntu1904 + - workflow_ubuntu2004: &workflow_ubuntu2004 <<: *workflow_trigger_on_tags requires: - b_ubu @@ -189,17 +191,17 @@ defaults: requires: - b_ubu_ossfuzz - - workflow_ubuntu1904_clang: &workflow_ubuntu1904_clang + - workflow_ubuntu2004_clang: &workflow_ubuntu2004_clang <<: *workflow_trigger_on_tags requires: - b_ubu_clang - - workflow_ubuntu1904_release: &workflow_ubuntu1904_release + - workflow_ubuntu2004_release: &workflow_ubuntu2004_release <<: *workflow_trigger_on_tags requires: - b_ubu_release - - workflow_ubuntu1904_codecov: &workflow_ubuntu1904_codecov + - workflow_ubuntu2004_codecov: &workflow_ubuntu2004_codecov <<: *workflow_trigger_on_tags requires: - b_ubu_codecov @@ -209,7 +211,7 @@ defaults: requires: - b_osx - - workflow_ubuntu1904_asan: &workflow_ubuntu1904_asan + - workflow_ubuntu2004_asan: &workflow_ubuntu2004_asan <<: *workflow_trigger_on_tags requires: - b_ubu_asan @@ -359,16 +361,16 @@ jobs: chk_docs_pragma_min_version: docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> environment: TERM: xterm steps: - checkout - run: *run_docs_pragma_min_version - b_ubu_clang: &build_ubuntu1904_clang + b_ubu_clang: &build_ubuntu2004_clang docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-<< pipeline.parameters.ubuntu-1904-clang-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-clang-<< pipeline.parameters.ubuntu-2004-clang-docker-image-rev >> environment: CC: clang CXX: clang++ @@ -378,9 +380,9 @@ jobs: - store_artifacts: *artifacts_solc - persist_to_workspace: *artifacts_executables - b_ubu: &build_ubuntu1904 + b_ubu: &build_ubuntu2004 docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> steps: - checkout - run: *run_build @@ -388,8 +390,8 @@ jobs: - store_artifacts: *artifacts_tools - persist_to_workspace: *artifacts_executables - b_ubu_release: &build_ubuntu1904_release - <<: *build_ubuntu1904 + b_ubu_release: &build_ubuntu2004_release + <<: *build_ubuntu2004 environment: FORCE_RELEASE: ON @@ -406,7 +408,7 @@ jobs: - persist_to_workspace: *artifacts_executables b_ubu_codecov: - <<: *build_ubuntu1904 + <<: *build_ubuntu2004 environment: COVERAGE: ON CMAKE_BUILD_TYPE: Debug @@ -416,7 +418,7 @@ jobs: - persist_to_workspace: *artifacts_build_dir t_ubu_codecov: - <<: *test_ubuntu1904 + <<: *test_ubuntu2004 environment: EVM: constantinople OPTIMIZE: 1 @@ -439,7 +441,7 @@ jobs: # Builds in C++20 mode and uses debug build in order to speed up. # Do *NOT* store any artifacts or workspace as we don't run tests on this build. b_ubu_cxx20: - <<: *build_ubuntu1904 + <<: *build_ubuntu2004 environment: CMAKE_BUILD_TYPE: Debug CMAKE_OPTIONS: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cxx20.cmake -DUSE_CVC4=OFF @@ -591,7 +593,7 @@ jobs: # x64 ASAN build, for testing for memory related bugs b_ubu_asan: &b_ubu_asan - <<: *build_ubuntu1904 + <<: *build_ubuntu2004 environment: CMAKE_OPTIONS: -DSANITIZE=address CMAKE_BUILD_TYPE: Release @@ -603,7 +605,7 @@ jobs: b_docs: docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> steps: - checkout - run: *setup_prerelease_commit_hash @@ -615,10 +617,27 @@ jobs: destination: docs-html t_ubu_soltest: &t_ubu_soltest - <<: *test_ubuntu1904 + <<: *test_ubuntu2004 + + t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul + docker: + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> + environment: + EVM: constantinople + SOLTEST_FLAGS: --enforce-via-yul + OPTIMIZE: 0 + TERM: xterm + steps: + - checkout + - attach_workspace: + at: build + - run: *run_soltest + - store_test_results: *store_test_results + - store_artifacts: *artifacts_test_results + t_ubu_clang_soltest: &t_ubu_clang_soltest - <<: *test_ubuntu1904_clang + <<: *test_ubuntu2004_clang environment: EVM: constantinople OPTIMIZE: 0 @@ -628,7 +647,7 @@ jobs: t_ubu_cli: &t_ubu_cli docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> environment: TERM: xterm steps: @@ -816,20 +835,21 @@ workflows: # Ubuntu build and tests - b_ubu: *workflow_trigger_on_tags - b_ubu18: *workflow_trigger_on_tags - - t_ubu_cli: *workflow_ubuntu1904 - - t_ubu_soltest: *workflow_ubuntu1904 + - t_ubu_cli: *workflow_ubuntu2004 + - t_ubu_soltest: *workflow_ubuntu2004 + - t_ubu_soltest_enforce_yul: *workflow_ubuntu2004 - b_ubu_clang: *workflow_trigger_on_tags - - t_ubu_clang_soltest: *workflow_ubuntu1904_clang + - t_ubu_clang_soltest: *workflow_ubuntu2004_clang # Ubuntu fake release build and tests - b_ubu_release: *workflow_trigger_on_tags - - t_ubu_release_cli: *workflow_ubuntu1904_release - - t_ubu_release_soltest: *workflow_ubuntu1904_release + - t_ubu_release_cli: *workflow_ubuntu2004_release + - t_ubu_release_soltest: *workflow_ubuntu2004_release # ASan build and tests - b_ubu_asan: *workflow_trigger_on_tags - - t_ubu_asan_constantinople: *workflow_ubuntu1904_asan - - t_ubu_asan_cli: *workflow_ubuntu1904_asan + - t_ubu_asan_constantinople: *workflow_ubuntu2004_asan + - t_ubu_asan_cli: *workflow_ubuntu2004_asan # Emscripten build and selected tests - b_ems: *workflow_trigger_on_tags @@ -856,4 +876,4 @@ workflows: # Code Coverage enabled build and tests - b_ubu_codecov: *workflow_trigger_on_tags - - t_ubu_codecov: *workflow_ubuntu1904_codecov + - t_ubu_codecov: *workflow_ubuntu2004_codecov diff --git a/.circleci/docker/Dockerfile.ubuntu1904.clang b/.circleci/docker/Dockerfile.ubuntu1904.clang deleted file mode 100644 index cf790c84ea79..000000000000 --- a/.circleci/docker/Dockerfile.ubuntu1904.clang +++ /dev/null @@ -1,113 +0,0 @@ -# vim:syntax=dockerfile -#------------------------------------------------------------------------------ -# Dockerfile for building and testing Solidity Compiler on CI -# Target: Ubuntu 19.04 (Disco Dingo) Clang variant -# URL: https://hub.docker.com/r/ethereum/solidity-buildpack-deps -# -# This file is part of solidity. -# -# solidity is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# solidity is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with solidity. If not, see -# -# (c) 2016-2019 solidity contributors. -#------------------------------------------------------------------------------ -FROM buildpack-deps:disco AS base - -ARG DEBIAN_FRONTEND=noninteractive - -RUN set -ex; \ - dist=$(grep DISTRIB_CODENAME /etc/lsb-release | cut -d= -f2); \ - echo "deb http://ppa.launchpad.net/ethereum/cpp-build-deps/ubuntu $dist main" >> /etc/apt/sources.list ; \ - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1c52189c923f6ca9 ; \ - apt-get update; \ - apt-get install -qqy --no-install-recommends \ - build-essential \ - software-properties-common \ - cmake ninja-build \ - clang++-8 llvm-8-dev \ - libjsoncpp-dev \ - libleveldb1d \ - ; \ - apt-get install -qy python-pip python-sphinx; \ - update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-8 1; \ - update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 1; \ - update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 1; \ - pip install codecov; \ - rm -rf /var/lib/apt/lists/* - -FROM base AS libraries - -ENV CC clang -ENV CXX clang++ - -# Boost -RUN git clone -b boost-1.69.0 https://github.com/boostorg/boost.git \ - /usr/src/boost; \ - cd /usr/src/boost; \ - git submodule update --init --recursive; \ - ./bootstrap.sh --with-toolset=clang --prefix=/usr; \ - ./b2 toolset=clang headers; \ - ./b2 toolset=clang variant=release \ - system filesystem unit_test_framework program_options \ - install -j $(($(nproc)/2)); \ - rm -rf /usr/src/boost - -# Z3 -RUN git clone --depth 1 -b z3-4.8.7 https://github.com/Z3Prover/z3.git \ - /usr/src/z3; \ - cd /usr/src/z3; \ - python scripts/mk_make.py --prefix=/usr ; \ - cd build; \ - make -j; \ - make install; \ - rm -rf /usr/src/z3; - -# OSSFUZZ: libprotobuf-mutator -RUN set -ex; \ - git clone https://github.com/google/libprotobuf-mutator.git \ - /usr/src/libprotobuf-mutator; \ - cd /usr/src/libprotobuf-mutator; \ - git checkout 3521f47a2828da9ace403e4ecc4aece1a84feb36; \ - mkdir build; \ - cd build; \ - cmake .. -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ - -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="/usr"; \ - ninja; \ - cp -vpr external.protobuf/bin/* /usr/bin/; \ - cp -vpr external.protobuf/include/* /usr/include/; \ - cp -vpr external.protobuf/lib/* /usr/lib/; \ - ninja install/strip; \ - rm -rf /usr/src/libprotobuf-mutator - -# EVMONE -RUN set -ex; \ - cd /usr/src; \ - git clone --branch="v0.4.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ - cd evmone; \ - mkdir build; \ - cd build; \ - # isoltest links against the evmone shared library - cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ - ninja; \ - ninja install/strip; \ - # abiv2_proto_ossfuzz links against the evmone standalone static library - cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="/usr" ..; \ - ninja; \ - ninja install/strip; \ - rm -rf /usr/src/evmone - -FROM base -COPY --from=libraries /usr/lib /usr/lib -COPY --from=libraries /usr/bin /usr/bin -COPY --from=libraries /usr/include /usr/include diff --git a/.circleci/docker/Dockerfile.ubuntu1904 b/.circleci/docker/Dockerfile.ubuntu2004 similarity index 52% rename from .circleci/docker/Dockerfile.ubuntu1904 rename to .circleci/docker/Dockerfile.ubuntu2004 index 903b6945beb5..d39025809123 100644 --- a/.circleci/docker/Dockerfile.ubuntu1904 +++ b/.circleci/docker/Dockerfile.ubuntu2004 @@ -21,59 +21,26 @@ # # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ -FROM buildpack-deps:disco AS base +FROM buildpack-deps:focal AS base ARG DEBIAN_FRONTEND=noninteractive RUN set -ex; \ - dist=$(grep DISTRIB_CODENAME /etc/lsb-release | cut -d= -f2); \ - echo "deb http://ppa.launchpad.net/ethereum/cpp-build-deps/ubuntu $dist main" >> /etc/apt/sources.list ; \ - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1c52189c923f6ca9 ; \ apt-get update; \ apt-get install -qqy --no-install-recommends \ build-essential \ software-properties-common \ - cmake ninja-build clang++-8 libc++-8-dev libc++abi-8-dev \ + cmake ninja-build \ libboost-filesystem-dev libboost-test-dev libboost-system-dev \ libboost-program-options-dev \ - libjsoncpp-dev \ - llvm-8-dev libcvc4-dev libz3-static-dev libleveldb1d \ + libcvc4-dev z3 libz3-dev \ ; \ - apt-get install -qy python-pip python-sphinx; \ - update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-8 1; \ - pip install codecov; \ + apt-get install -qy python3-pip python3-sphinx; \ + pip3 install codecov; \ rm -rf /var/lib/apt/lists/* FROM base AS libraries -# OSSFUZZ: libprotobuf-mutator -RUN set -ex; \ - git clone https://github.com/google/libprotobuf-mutator.git \ - /usr/src/libprotobuf-mutator; \ - cd /usr/src/libprotobuf-mutator; \ - git checkout d1fe8a7d8ae18f3d454f055eba5213c291986f21; \ - mkdir build; \ - cd build; \ - cmake .. -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ - -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="/usr"; \ - ninja; \ - cp -vpr external.protobuf/bin/* /usr/bin/; \ - cp -vpr external.protobuf/include/* /usr/include/; \ - cp -vpr external.protobuf/lib/* /usr/lib/; \ - ninja install/strip; \ - rm -rf /usr/src/libprotobuf-mutator - -# OSSFUZZ: libfuzzer -RUN set -ex; \ - cd /var/tmp; \ - svn co https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libfuzzer; \ - mkdir -p build-libfuzzer; \ - cd build-libfuzzer; \ - clang++-8 -O1 -stdlib=libstdc++ -std=c++11 -O2 -fPIC -c ../libfuzzer/*.cpp -I../libfuzzer; \ - ar r /usr/lib/libFuzzingEngine.a *.o; \ - rm -rf /var/lib/libfuzzer - # EVMONE RUN set -ex; \ cd /usr/src; \ @@ -81,7 +48,6 @@ RUN set -ex; \ cd evmone; \ mkdir build; \ cd build; \ - # isoltest links against the evmone shared library cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ ninja; \ ninja install/strip; \ diff --git a/.circleci/docker/Dockerfile.ubuntu2004.clang b/.circleci/docker/Dockerfile.ubuntu2004.clang new file mode 100644 index 000000000000..f436c34b7647 --- /dev/null +++ b/.circleci/docker/Dockerfile.ubuntu2004.clang @@ -0,0 +1,61 @@ +# vim:syntax=dockerfile +#------------------------------------------------------------------------------ +# Dockerfile for building and testing Solidity Compiler on CI +# Target: Ubuntu 19.04 (Disco Dingo) Clang variant +# URL: https://hub.docker.com/r/ethereum/solidity-buildpack-deps +# +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2016-2019 solidity contributors. +#------------------------------------------------------------------------------ +FROM buildpack-deps:focal AS base + +ARG DEBIAN_FRONTEND=noninteractive + +RUN set -ex; \ + apt-get update; \ + apt-get install -qqy --no-install-recommends \ + build-essential \ + software-properties-common \ + cmake ninja-build \ + libboost-filesystem-dev libboost-test-dev libboost-system-dev \ + libboost-program-options-dev \ + clang llvm-dev \ + z3 libz3-dev \ + ; \ + rm -rf /var/lib/apt/lists/* + +FROM base AS libraries + +ENV CC clang +ENV CXX clang++ + +# EVMONE +RUN set -ex; \ + cd /usr/src; \ + git clone --branch="v0.4.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ + cd evmone; \ + mkdir build; \ + cd build; \ + cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ + ninja; \ + ninja install/strip; \ + rm -rf /usr/src/evmone + +FROM base +COPY --from=libraries /usr/lib /usr/lib +COPY --from=libraries /usr/bin /usr/bin +COPY --from=libraries /usr/include /usr/include diff --git a/.circleci/soltest.sh b/.circleci/soltest.sh index 948c79deecea..f55239e60362 100755 --- a/.circleci/soltest.sh +++ b/.circleci/soltest.sh @@ -57,7 +57,7 @@ get_logfile_basename() { BOOST_TEST_ARGS="--color_output=no --show_progress=yes --logger=JUNIT,error,test_results/`get_logfile_basename`.xml" SOLTEST_ARGS="--evm-version=$EVM $SOLTEST_FLAGS" test "${OPTIMIZE}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --optimize" -test "${ABI_ENCODER_V2}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --abiencoderv2 --optimize-yul" +test "${ABI_ENCODER_V2}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --abiencoderv2" echo "Running ${REPODIR}/build/test/soltest ${BOOST_TEST_ARGS} -- ${SOLTEST_ARGS}" diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a5026bad6d2..ee698a715025 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.6.7") +set(PROJECT_VERSION "0.6.8") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/Changelog.md b/Changelog.md index 21d45156c13b..48eea359754e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,30 @@ +### 0.6.8 (2020-05-14) + +Important Bugfixes: + * Add missing callvalue check to the creation code of a contract that does not define a constructor but has a base that does define a constructor. + * Disallow array slices of arrays with dynamically encoded base types. + * String literals containing backslash characters can no longer cause incorrect code to be generated when passed directly to function calls or encoding functions when ABIEncoderV2 is active. + + +Language Features: + * Implemented ``type(T).min`` and ``type(T).max`` for every integer type ``T`` that returns the smallest and largest value representable by the type. + + +Compiler Features: + * Commandline Interface: Don't ignore `--yul-optimizations` in assembly mode. + * Allow using abi encoding functions for calldata array slices without explicit casts. + * Wasm binary output: Implement ``br`` and ``br_if``. + + +Bugfixes: + * ABI: Skip ``private`` or ``internal`` constructors. + * Fixed an "Assembly Exception in Bytecode" error where requested functions were generated twice. + * Natspec: Fixed a bug that ignored ``@return`` tag when no other developer-documentation tags were present. + * Type Checker: Checks if a literal exponent in the ``**`` operation is too large or fractional. + * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. + * Yul Assembler: Fix source location of variable declarations without value. + + ### 0.6.7 (2020-05-04) Language Features: diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index 9461cb6bd6bd..68d917f9f0dd 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -292,6 +292,7 @@ Consider you have the following pre-0.5.0 contract already deployed: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.4.25; // This will report a warning until version 0.4.25 of the compiler // This will not compile after 0.5.0 @@ -309,6 +310,7 @@ This will no longer compile with Solidity v0.5.0. However, you can define a comp :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; interface OldContract { function someOldFunction(uint8 a) external; @@ -326,6 +328,7 @@ Given the interface defined above, you can now easily use the already deployed p :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; interface OldContract { @@ -347,6 +350,7 @@ commandline compiler for linking): :: // This will not compile after 0.6.0 + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.5.99; library OldLibrary { @@ -370,6 +374,7 @@ Old version: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.4.25; // This will not compile after 0.5.0 @@ -432,6 +437,7 @@ New version: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.5.99; // This will not compile after 0.6.0 diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index ec31654dd710..1d3e8efd08c6 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -232,6 +232,7 @@ Given the contract: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Foo { @@ -535,6 +536,7 @@ For example, :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; @@ -583,6 +585,7 @@ As an example, the code :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.19 <0.7.0; pragma experimental ABIEncoderV2; diff --git a/docs/assembly.rst b/docs/assembly.rst index 19e4449e6c12..c42e9d70d478 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -41,6 +41,7 @@ without a compiler change. .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; library GetCode { @@ -66,6 +67,7 @@ efficient code, for example: .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; @@ -136,6 +138,7 @@ Local Solidity variables are available for assignments, for example: .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { diff --git a/docs/bugs.json b/docs/bugs.json index 56bae3aaffff..90f211c1f7cc 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,34 @@ [ + { + "name": "MissingEscapingInFormatting", + "summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.", + "description": "When ABIEncoderV2 is enabled, string literals passed directly to encoding functions or external function calls are stored as strings in the intemediate code. Characters outside the printable range are handled correctly, but backslashes are not escaped in this procedure. This leads to double backslashes being reduced to single backslashes and consequently re-interpreted as escapes potentially resulting in a different string being encoded.", + "introduced": "0.5.14", + "fixed": "0.6.8", + "severity": "very low", + "conditions": { + "ABIEncoderV2": true + } + }, + { + "name": "ArraySliceDynamicallyEncodedBaseType", + "summary": "Accessing array slices of arrays with dynamically encoded base types (e.g. multi-dimensional arrays) can result in invalid data being read.", + "description": "For arrays with dynamically sized base types, index range accesses that use a start expression that is non-zero will result in invalid array slices. Any index access to such array slices will result in data being read from incorrect calldata offsets. Array slices are only supported for dynamic calldata types and all problematic type require ABIEncoderV2 to be enabled.", + "introduced": "0.6.0", + "fixed": "0.6.8", + "severity": "very low", + "conditions": { + "ABIEncoderV2": true + } + }, + { + "name": "ImplicitConstructorCallvalueCheck", + "summary": "The creation code of a contract that does not define a constructor but has a base that does define a constructor did not revert for calls with non-zero value.", + "description": "Starting from Solidity 0.4.5 the creation code of contracts without explicit payable constructor is supposed to contain a callvalue check that results in contract creation reverting, if non-zero value is passed. However, this check was missing in case no explicit constructor was defined in a contract at all, but the contract has a base that does define a constructor. In these cases it is possible to send value in a contract creation transaction or using inline assembly without revert, even though the creation code is supposed to be non-payable.", + "introduced": "0.4.5", + "fixed": "0.6.8", + "severity": "very low" + }, { "name": "TupleAssignmentMultiStackSlotComponents", "summary": "Tuple assignments with components that occupy several stack slots, i.e. nested tuples, pointers to external functions or references to dynamically sized calldata arrays, can result in invalid values.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 4c27e90d95a6..248517b8bed9 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -415,6 +415,7 @@ }, "0.4.10": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -433,6 +434,7 @@ }, "0.4.11": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -450,6 +452,7 @@ }, "0.4.12": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -466,6 +469,7 @@ }, "0.4.13": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -482,6 +486,7 @@ }, "0.4.14": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -497,6 +502,7 @@ }, "0.4.15": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -511,6 +517,7 @@ }, "0.4.16": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -527,6 +534,7 @@ }, "0.4.17": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -544,6 +552,7 @@ }, "0.4.18": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -560,6 +569,7 @@ }, "0.4.19": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -596,6 +606,7 @@ }, "0.4.20": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -613,6 +624,7 @@ }, "0.4.21": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -630,6 +642,7 @@ }, "0.4.22": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -647,6 +660,7 @@ }, "0.4.23": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -663,6 +677,7 @@ }, "0.4.24": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -679,6 +694,7 @@ }, "0.4.25": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -693,6 +709,7 @@ }, "0.4.26": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -739,6 +756,7 @@ }, "0.4.5": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -758,6 +776,7 @@ }, "0.4.6": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -776,6 +795,7 @@ }, "0.4.7": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -794,6 +814,7 @@ }, "0.4.8": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -812,6 +833,7 @@ }, "0.4.9": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -830,6 +852,7 @@ }, "0.5.0": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -844,6 +867,7 @@ }, "0.5.1": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -858,6 +882,7 @@ }, "0.5.10": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -868,6 +893,7 @@ }, "0.5.11": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -877,6 +903,7 @@ }, "0.5.12": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -886,6 +913,7 @@ }, "0.5.13": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -895,6 +923,8 @@ }, "0.5.14": { "bugs": [ + "MissingEscapingInFormatting", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -905,6 +935,8 @@ }, "0.5.15": { "bugs": [ + "MissingEscapingInFormatting", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -914,6 +946,8 @@ }, "0.5.16": { "bugs": [ + "MissingEscapingInFormatting", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden" @@ -922,6 +956,8 @@ }, "0.5.17": { "bugs": [ + "MissingEscapingInFormatting", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -929,6 +965,7 @@ }, "0.5.2": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -943,6 +980,7 @@ }, "0.5.3": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -957,6 +995,7 @@ }, "0.5.4": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -971,6 +1010,7 @@ }, "0.5.5": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -987,6 +1027,7 @@ }, "0.5.6": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1003,6 +1044,7 @@ }, "0.5.7": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1017,6 +1059,7 @@ }, "0.5.8": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1030,6 +1073,7 @@ }, "0.5.9": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1042,6 +1086,9 @@ }, "0.6.0": { "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "YulOptimizerRedundantAssignmentBreakContinue" @@ -1050,6 +1097,9 @@ }, "0.6.1": { "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1057,6 +1107,9 @@ }, "0.6.2": { "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1064,6 +1117,9 @@ }, "0.6.3": { "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1071,6 +1127,9 @@ }, "0.6.4": { "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1078,16 +1137,31 @@ }, "0.6.5": { "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents" ], "released": "2020-04-06" }, "0.6.6": { - "bugs": [], + "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck" + ], "released": "2020-04-09" }, "0.6.7": { - "bugs": [], + "bugs": [ + "MissingEscapingInFormatting", + "ArraySliceDynamicallyEncodedBaseType", + "ImplicitConstructorCallvalueCheck" + ], "released": "2020-05-04" + }, + "0.6.8": { + "bugs": [], + "released": "2020-05-14" } } \ No newline at end of file diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index 5d6169a48251..5e673f7b0b86 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -122,6 +122,8 @@ Global Variables - ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information`. - ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information`. - ``type(I).interfaceId`` (``bytes4``): value containing the EIP-165 interface identifier of the given interface, see :ref:`Type Information`. +- ``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:: Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness, diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index ab25cb4b9ec9..ad33c52fc328 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -27,6 +27,7 @@ you receive the funds of the person who is now the richest. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract WithdrawalContract { @@ -60,6 +61,7 @@ This is as opposed to the more intuitive sending pattern: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract SendContract { @@ -121,6 +123,7 @@ restrictions highly readable. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract AccessRestriction { @@ -273,6 +276,7 @@ function finishes. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract StateMachine { diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst index 4571f45b2c85..908fa5072976 100644 --- a/docs/contracts/abstract-contracts.rst +++ b/docs/contracts/abstract-contracts.rst @@ -13,6 +13,7 @@ This can be done by using the ``abstract`` keyword as shown in the following exa defined as abstract, because the function ``utterance()`` was defined, but no implementation was provided (no implementation body ``{ }`` was given).:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; abstract contract Feline { @@ -22,6 +23,7 @@ provided (no implementation body ``{ }`` was given).:: Such abstract contracts can not be instantiated directly. This is also true, if an abstract contract itself does implement all defined functions. The usage of an abstract contract as a base class is shown in the following example:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; abstract contract Feline { diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 7a0a7380a555..7424cd66aacb 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -17,6 +17,7 @@ Not all types for constants and immutables are implemented at this time. The onl :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >0.6.4 <0.7.0; contract C { diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst index 90578f784768..a2a628237140 100644 --- a/docs/contracts/creating-contracts.rst +++ b/docs/contracts/creating-contracts.rst @@ -34,6 +34,7 @@ This means that cyclic creation dependencies are impossible. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst index 46b426d8e66b..e4e74bde4773 100644 --- a/docs/contracts/events.rst +++ b/docs/contracts/events.rst @@ -65,6 +65,7 @@ is that they are cheaper to deploy and call. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.21 <0.7.0; contract ClientReceipt { @@ -138,6 +139,7 @@ as topics. The event call above can be performed in the same way as :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.10 <0.7.0; contract C { diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst index 758ba74eaa9f..b64143d90074 100644 --- a/docs/contracts/function-modifiers.rst +++ b/docs/contracts/function-modifiers.rst @@ -17,6 +17,7 @@ if they are marked ``virtual``. For details, please see :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract owned { diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 7a0ec2e08559..f33258fe1884 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -23,6 +23,7 @@ unused parameters can be omitted. For example, if you want your contract to accept one kind of external call with two integers, you would use something like the following:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Simple { @@ -55,6 +56,7 @@ Function return variables are declared with the same syntax after the For example, suppose you want to return two results: the sum and the product of two integers passed as function parameters, then you use something like:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Simple { @@ -79,6 +81,7 @@ or you can provide return values (either a single or :ref:`multiple ones`) directly with the ``return`` statement:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Simple { @@ -142,6 +145,7 @@ The following statements are considered modifying the state: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -187,6 +191,7 @@ In addition to the list of state modifying statements explained above, the follo :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -280,6 +285,7 @@ Below you can see an example of a Sink contract that uses function ``receive``. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; // This contract keeps all Ether sent to it with no way @@ -335,6 +341,7 @@ operations as long as there is enough gas passed on to it. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract Test { @@ -407,6 +414,7 @@ The following example shows overloading of the function :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract A { @@ -425,6 +433,7 @@ externally visible functions differ by their Solidity types but not by their ext :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; // This will not compile @@ -458,6 +467,7 @@ candidate, resolution fails. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract A { diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index d3dd0f1647db..83ccdf773bcc 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -38,6 +38,7 @@ Details are given in the following example. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; @@ -125,6 +126,7 @@ Note that above, we call ``Destructible.destroy()`` to "forward" the destruction request. The way this is done is problematic, as seen in the following example:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; contract owned { @@ -154,6 +156,7 @@ A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it explicitly in the final override, but this function will bypass ``Base1.destroy``. The way around this is to use ``super``:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract owned { @@ -204,6 +207,7 @@ use the ``override`` keyword in the function header as shown in this example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base @@ -227,6 +231,7 @@ bases, it has to explicitly override it: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base1 @@ -253,6 +258,7 @@ that already overrides all other functions. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract A { function f() public pure{} } @@ -293,6 +299,7 @@ of the variable: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract A @@ -324,6 +331,7 @@ and the ``override`` keyword must be used in the overriding modifier: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base @@ -342,6 +350,7 @@ explicitly: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base1 @@ -389,6 +398,7 @@ equivalent to ``constructor() public {}``. For example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract A { @@ -419,6 +429,7 @@ The constructors of all the base contracts will be called following the linearization rules explained below. If the base constructors have arguments, derived contracts need to specify all of them. This can be done in two ways:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract Base { @@ -478,6 +489,7 @@ error "Linearization of inheritance graph impossible". :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract X {} @@ -498,6 +510,7 @@ One area where inheritance linearization is especially important and perhaps not :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract Base1 { diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index bce974502f90..7b1421791ffa 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -22,6 +22,7 @@ Interfaces are denoted by their own keyword: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; interface Token { @@ -42,6 +43,7 @@ inheritance. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; interface ParentA { diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 86561ea7b2e4..f58bf0f4e806 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -47,6 +47,7 @@ more advanced example to implement a set). :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; @@ -125,6 +126,7 @@ custom types without the overhead of external function calls: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; struct bigint { @@ -239,6 +241,7 @@ Its value can be obtained from Solidity using the ``.selector`` member as follow :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.14 <0.7.0; library L { diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 9e63abcf4ed7..8853bad24160 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -29,6 +29,7 @@ may only be used inside a contract, not inside any of its functions. Let us rewrite the set example from the :ref:`libraries` in this way:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; @@ -81,6 +82,7 @@ Let us rewrite the set example from the It is also possible to extend elementary types in that way:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; library Search { diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst index 04af8a26f2e7..7e7785f3af5f 100644 --- a/docs/contracts/visibility-and-getters.rst +++ b/docs/contracts/visibility-and-getters.rst @@ -54,6 +54,7 @@ return parameter list for functions. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -68,6 +69,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -112,6 +114,7 @@ when they are declared. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -132,6 +135,7 @@ it evaluates to a state variable. If it is accessed externally :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract C { @@ -151,6 +155,7 @@ to write a function, for example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract arrayExample { @@ -177,6 +182,7 @@ The next example is more complex: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Complex { diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 7bbe290ba35e..9ecaa838bda6 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -41,6 +41,7 @@ Internal Function Calls Functions of the current contract can be called directly ("internally"), also recursively, as seen in this nonsensical example:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract C { @@ -82,6 +83,7 @@ to the total balance of that contract: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract InfoFeed { @@ -137,6 +139,7 @@ parameters from the function declaration, but can be in arbitrary order. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract C { @@ -160,6 +163,7 @@ Those parameters will still be present on the stack, but they are inaccessible. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract C { @@ -183,6 +187,7 @@ is compiled so recursive creation-dependencies are not possible. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract D { @@ -238,6 +243,7 @@ which only need to be created if there is a dispute. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract D { @@ -307,6 +313,7 @@ groupings of expressions. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -352,6 +359,7 @@ because only a reference and not a copy is passed. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract C { @@ -410,6 +418,7 @@ the two variables have the same name but disjoint scopes. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { function minimalScoping() pure public { @@ -431,6 +440,7 @@ In any case, you will get a warning about the outer variable being shadowed. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; // This will report a warning contract C { @@ -452,6 +462,7 @@ In any case, you will get a warning about the outer variable being shadowed. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; // This will not compile contract C { @@ -540,6 +551,7 @@ and ``assert`` for internal error checking. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract Sharer { @@ -584,6 +596,7 @@ The following example shows how to use an error string together with ``revert`` :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract VendingMachine { @@ -627,6 +640,7 @@ A failure in an external call can be caught using a try/catch statement, as foll :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; interface DataFeed { function getData(address token) external returns (uint value); } diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index f2034272a889..30c177baafab 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -24,6 +24,7 @@ to receive their money - contracts cannot activate themselves. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract SimpleAuction { @@ -184,6 +185,7 @@ invalid bids. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract BlindAuction { diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index ab69fd296be6..93dcd26f0efe 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -142,6 +142,7 @@ The full contract :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.24 <0.7.0; contract ReceiverPays { @@ -338,6 +339,7 @@ The full contract :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract SimplePaymentChannel { diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst index a95a675c61ff..ff6a64077b92 100644 --- a/docs/examples/modular.rst +++ b/docs/examples/modular.rst @@ -19,6 +19,7 @@ and the sum of all balances is an invariant across the lifetime of the contract. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; library Balances { diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst index caafaa7edbbe..c8e0eecc1694 100644 --- a/docs/examples/safe-remote.rst +++ b/docs/examples/safe-remote.rst @@ -25,6 +25,7 @@ you can use state machine-like constructs inside a contract. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract Purchase { diff --git a/docs/examples/voting.rst b/docs/examples/voting.rst index e4b6da200809..8d97a57ee3a0 100644 --- a/docs/examples/voting.rst +++ b/docs/examples/voting.rst @@ -32,6 +32,7 @@ of votes. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; /// @title Voting with delegation. diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index 0101556ef836..5e102a38a923 100644 --- a/docs/internals/layout_in_storage.rst +++ b/docs/internals/layout_in_storage.rst @@ -71,6 +71,7 @@ So for the following contract snippet the position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1``:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; @@ -171,6 +172,7 @@ value and reference types, types that are encoded packed, and nested types. .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { struct S { diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index e3e38b92c697..6a59f1373351 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -17,6 +17,7 @@ Storage Example :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract SimpleStorage { @@ -31,8 +32,12 @@ Storage Example } } -The first line tells you that the source code is written for -Solidity version 0.4.0, or a newer version of the language up to, but not including version 0.7.0. +The first line tells you that the source code is licensed under the +GPL version 3.0. Machine-readable license specifiers are important +in a setting where publishing the source code is the default. + +The next line specifies that the source code is written for +Solidity version 0.4.16, or a newer version of the language up to, but not including version 0.7.0. This is to ensure that the contract is not compilable with a new (breaking) compiler version, where it could behave differently. :ref:`Pragmas` are common instructions for compilers about how to treat the source code (e.g. `pragma once `_). @@ -77,6 +82,7 @@ registering with a username and password, all you need is an Ethereum keypair. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract Coin { diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index a2629319bd90..f01e23ac5a18 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -7,6 +7,38 @@ Source files can contain an arbitrary number of :ref:`pragma directives` and :ref:`struct` and :ref:`enum` definitions. +.. index:: ! license, spdx + +SPDX License Identifier +======================= + +Trust in smart contract can be better established if their source code +is available. Since making source code available always touches on legal problems +with regards to copyright, the Solidity compiler encouranges the use +of machine-readable `SPDX license identifiers `_. +Every source file should start with a comment indicating its license: + +``// SPDX-License-Identifier: MIT`` + +The compiler does not validate that the license is part of the +`list allowed by SPDX `_, but +it does include the supplied string in the `bytecode metadata `_. + +If you do not want to specify a license or if the source code is +not open-source, please use the special value ``UNLICENSED``. + +Supplying this comment of course does not free you from other +obligations related to licensing like having to mention +a specific license header in each source file or the +original copyright holder. + +The comment is recognized by the compiler anywhere in the file at the +file level, but it is recommended to put it at the top of the file. + +More information about how to use SPDX license identifiers +can be found at the `SPDX website `_. + + .. index:: ! pragma .. _pragma: @@ -284,6 +316,7 @@ for the two function parameters and two return variables. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.21 <0.7.0; /** @title Shape calculator. */ diff --git a/docs/metadata.rst b/docs/metadata.rst index 0c8ae47f1732..240814adca53 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -1,3 +1,5 @@ +.. _metadata: + ################# Contract Metadata ################# @@ -54,7 +56,9 @@ explanatory purposes. // Required (unless "content" is used, see below): Sorted URL(s) // to the source file, protocol is more or less arbitrary, but a // Swarm URL is recommended - "urls": [ "bzzr://56ab..." ] + "urls": [ "bzzr://56ab..." ], + // Optional: SPDX license identifier as given in the source file + "license": "MIT" }, "destructible": { // Required: keccak256 hash of the source file @@ -82,8 +86,12 @@ explanatory purposes. deduplicate: false, cse: false, constantOptimizer: false, - yul: false, - yulDetails: {} + yul: true, + // Optional: Only present if "yul" is "true" + yulDetails: { + stackAllocation: false, + optimizerSteps: "dhfoDgvulfnTUtnIf..." + } } }, metadata: { diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 1776925ee947..fa1d0c665cce 100644 --- a/docs/natspec-format.rst +++ b/docs/natspec-format.rst @@ -49,6 +49,7 @@ The following example shows a contract and a function using all available tags. .. code:: solidity + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; /// @title A simulator for trees diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index cf706fb7b100..f899736aa9d0 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -58,6 +58,7 @@ complete contract): :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE @@ -81,6 +82,7 @@ as it uses ``call`` which forwards all remaining gas by default: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE @@ -100,6 +102,7 @@ outlined further below: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.11 <0.7.0; contract Fund { @@ -197,6 +200,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE @@ -217,6 +221,7 @@ Now someone tricks you into sending Ether to the address of this attack wallet: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; interface TxUserWallet { @@ -277,6 +282,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Map { @@ -555,6 +561,7 @@ not mean loss of proving power. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0; pragma experimental SMTChecker; // This may report a warning if no SMT solver available. @@ -609,6 +616,7 @@ types. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0; pragma experimental SMTChecker; // This will report a warning diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index b6d70c5a3250..8e744bef233c 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -26,6 +26,7 @@ storage. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract SimpleStorage { @@ -46,6 +47,7 @@ Functions are the executable units of code within a contract. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract SimpleAuction { @@ -74,6 +76,7 @@ Like functions, modifiers can be :ref:`overridden `. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract Purchase { @@ -101,6 +104,7 @@ Events are convenience interfaces with the EVM logging facilities. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.21 <0.7.0; contract SimpleAuction { @@ -125,6 +129,7 @@ Structs are custom defined types that can group several variables (see :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Ballot { @@ -146,6 +151,7 @@ Enums can be used to create custom types with a finite set of 'constant values' :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Purchase { diff --git a/docs/style-guide.rst b/docs/style-guide.rst index c2990824d812..9d51bb224220 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -55,6 +55,7 @@ Surround top level declarations in solidity source with two blank lines. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { @@ -73,6 +74,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { @@ -92,6 +94,7 @@ Blank lines may be omitted between groups of related one-liners (such as stub fu Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; abstract contract A { @@ -112,6 +115,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; abstract contract A { @@ -246,6 +250,7 @@ Import statements should always be placed at the top of the file. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; import "./Owned.sol"; @@ -260,6 +265,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { @@ -293,6 +299,7 @@ Within a grouping, place the ``view`` and ``pure`` functions last. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; contract A { @@ -329,6 +336,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; contract A { @@ -436,6 +444,7 @@ should: Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Coin { @@ -447,6 +456,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Coin @@ -747,6 +757,7 @@ manner as modifiers if the function declaration is long or hard to read. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; // Base contracts just to make this compile @@ -779,6 +790,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; @@ -1002,6 +1014,7 @@ As shown in the example below, if the contract name is ``Congress`` and the libr Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; @@ -1025,6 +1038,7 @@ Yes:: and in ``Congress.sol``:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; import "./Owned.sol"; @@ -1036,6 +1050,7 @@ and in ``Congress.sol``:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; @@ -1140,6 +1155,7 @@ multiline comment starting with ``/**`` and ending with ``*/``. For example, the contract from `a simple smart contract `_ with the comments added looks like the one below:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index d84da8ec5a4f..5226f36a3f1b 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -41,6 +41,7 @@ contract that returns the value at the specified address. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract MappingExample { @@ -66,6 +67,7 @@ The example below uses ``_allowances`` to record the amount someone else is allo :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract MappingExample { @@ -120,6 +122,7 @@ the ``sum`` function iterates over to sum all the values. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; struct IndexValue { uint keyIndex; uint value; } diff --git a/docs/types/operators.rst b/docs/types/operators.rst index c65e545c5446..76726ec6f83d 100644 --- a/docs/types/operators.rst +++ b/docs/types/operators.rst @@ -42,6 +42,7 @@ value it referred to previously. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract DeleteExample { diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index f7aca719037c..5a59997c43d4 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -57,6 +57,7 @@ Data locations are not only relevant for persistency of data, but also for the s :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -167,6 +168,7 @@ or create a new memory array and copy every element. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -198,6 +200,7 @@ the first element to ``uint``. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -214,6 +217,7 @@ memory arrays, i.e. the following is not possible: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; // This will not compile. @@ -274,6 +278,7 @@ Array Members :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract ArrayContract { @@ -406,6 +411,7 @@ Array slices are useful to ABI-decode secondary data passed in function paramete :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Proxy { @@ -443,6 +449,7 @@ shown in the following example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; // Defines a new type with two fields. diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 0301a8ad5633..29a91c83677b 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -40,6 +40,9 @@ Operators: * Shift operators: ``<<`` (left shift), ``>>`` (right shift) * Arithmetic operators: ``+``, ``-``, unary ``-``, ``*``, ``/``, ``%`` (modulo), ``**`` (exponentiation) +For an integer type ``X``, you can use ``type(X).min`` and ``type(X).max`` to +access the minimum and maximum value representable by the type. + .. warning:: Integers in Solidity are restricted to a certain range. For example, with ``uint32``, this is ``0`` up to ``2**32 - 1``. @@ -540,6 +543,7 @@ subsequent unsigned integer values starting from ``0``. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract test { @@ -650,6 +654,7 @@ External (or public) functions have the following members: Example that shows how to use the members:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; // This will report a warning @@ -668,6 +673,7 @@ Example that shows how to use the members:: Example that shows how to use internal function types:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; library ArrayUtils { @@ -725,6 +731,7 @@ Example that shows how to use internal function types:: Another example that uses external function types:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 54eed07a9799..d936ef2464a1 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -294,10 +294,11 @@ Furthermore, all functions of the current contract are callable directly includi Type Information ---------------- -The expression ``type(X)`` can be used to retrieve information about the -type ``X``. Currently, there is limited support for this feature, but -it might be expanded in the future. The following properties are -available for a contract type ``C``: +The expression ``type(X)`` can be used to retrieve information about the type +``X``. Currently, there is limited support for this feature (``X`` can be either +a contract or an integer type) but it might be expanded in the future. + +The following properties are available for a contract type ``C``: ``type(C).name`` The name of the contract. @@ -328,3 +329,10 @@ for an interface type ``I``: interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all function selectors defined within the interface itself - excluding all inherited functions. +The following properties are available for an integer type ``T``: + +``type(T).min`` + The smallest value representable by type ``T``. + +``type(T).max`` + The largest value representable by type ``T``. diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index ea573ed70989..9009fac016f7 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -231,7 +231,10 @@ Input Description "yulDetails": { // Improve allocation of stack slots for variables, can free up stack slots early. // Activated by default if the Yul optimizer is activated. - "stackAllocation": true + "stackAllocation": true, + // Select optimization steps to be applied. + // Optional, the optimizer will use the default sequence if omitted. + "optimizerSteps": "dhfoDgvulfnTUtnIf..." } } }, @@ -614,6 +617,7 @@ Assume you have the following contracts you want to update declared in ``Source. .. code-block:: none // This will not compile after 0.5.0 + // SPDX-License-Identifier: GPL-3.0 pragma solidity >0.4.23 <0.5.0; contract Updateable { @@ -695,6 +699,7 @@ The command above applies all changes as shown below. Please review them careful .. code-block:: solidity + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; abstract contract Updateable { diff --git a/docs/yul.rst b/docs/yul.rst index 2fcae1175612..2e8bc4a104d7 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -104,6 +104,8 @@ less-than comparison. } } +At the :ref:`end of the section `, a complete implementation of +the ERC-20 standard can be found. @@ -885,13 +887,6 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a | gaslimit() | | F | block gas limit of the current block | +-------------------------+-----+---+-----------------------------------------------------------------+ -There are three additional functions, ``datasize(x)``, ``dataoffset(x)`` and ``datacopy(t, f, l)``, -which are used to access other parts of a Yul object. - -``datasize`` and ``dataoffset`` can only take string literals (the names of other objects) -as arguments and return the size and offset in the data area, respectively. -For the EVM, the ``datacopy`` function is equivalent to ``codecopy``. - .. _yul-call-return-area: .. note:: @@ -903,6 +898,32 @@ For the EVM, the ``datacopy`` function is equivalent to ``codecopy``. The remaining bytes will retain their values as of before the call. If the call fails (it returns ``0``), nothing is written to that area, but you can still retrieve the failure data using ``returndatacopy``. + +In some internal dialects, there are additional functions: + +datasize, dataoffset, datacopy +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The functions ``datasize(x)``, ``dataoffset(x)`` and ``datacopy(t, f, l)``, +are used to access other parts of a Yul object. + +``datasize`` and ``dataoffset`` can only take string literals (the names of other objects) +as arguments and return the size and offset in the data area, respectively. +For the EVM, the ``datacopy`` function is equivalent to ``codecopy``. + + +setimmutable, loadimmutable +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The functions ``setimmutable("name", value)`` and ``loadimmutable("name")`` are +used for the immutable mechanism in Solidity and do not nicely map to pur Yul. +The function ``setimmutable`` assumes that the runtime code of a contract +is currently copied to memory at offsot zero. The call to ``setimmutable("name", value)`` +will store ``value`` at all points in memory that contain a call to +``loadimmutable("name")``. + + + .. _yul-object: Specification of Yul Object @@ -1015,3 +1036,253 @@ If you want to use Solidity in stand-alone Yul mode, you activate the optimizer solc --strict-assembly --optimize In Solidity mode, the Yul optimizer is activated together with the regular optimizer. + +Optimization step sequence +-------------------------- + +By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly. +You can override this sequence and supply your own using the ``--yul-optimizations`` option: + +.. code-block:: sh + + solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' + +The order of steps is significant and affects the quality of the output. +Moreover, applying a step may uncover new optimization opportunities for others that were already +applied so repeating steps is often beneficial. +By enclosing part of the sequence in square brackets (``[]``) you tell the optimizer to repeatedly +apply that part until it no longer improves the size of the resulting assembly. +You can use brackets multiple times in a single sequence but they cannot be nested. + +The following optimization steps are available: + +============ =============================== +Abbreviation Full name +============ =============================== +``f`` ``BlockFlattener`` +``l`` ``CircularReferencesPruner`` +``c`` ``CommonSubexpressionEliminator`` +``C`` ``ConditionalSimplifier`` +``U`` ``ConditionalUnsimplifier`` +``n`` ``ControlFlowSimplifier`` +``D`` ``DeadCodeEliminator`` +``v`` ``EquivalentFunctionCombiner`` +``e`` ``ExpressionInliner`` +``j`` ``ExpressionJoiner`` +``s`` ``ExpressionSimplifier`` +``x`` ``ExpressionSplitter`` +``I`` ``ForLoopConditionIntoBody`` +``O`` ``ForLoopConditionOutOfBody`` +``o`` ``ForLoopInitRewriter`` +``i`` ``FullInliner`` +``g`` ``FunctionGrouper`` +``h`` ``FunctionHoister`` +``T`` ``LiteralRematerialiser`` +``L`` ``LoadResolver`` +``M`` ``LoopInvariantCodeMotion`` +``r`` ``RedundantAssignEliminator`` +``m`` ``Rematerialiser`` +``V`` ``SSAReverser`` +``a`` ``SSATransform`` +``t`` ``StructuralSimplifier`` +``u`` ``UnusedPruner`` +``d`` ``VarDeclInitializer`` +============ =============================== + +Some steps depend on properties ensured by ``BlockFlattener``, ``FunctionGrouper``, ``ForLoopInitRewriter``. +For this reason the Yul optimizer always applies them before applying any steps supplied by the user. + + +.. _erc20yul: + +Complete ERC20 Example +====================== + +.. code-block:: yul + + object "Token" { + code { + // Store the creator in slot zero. + sstore(0, caller()) + + // Deploy the contract + datacopy(0, dataoffset("runtime"), datasize("runtime")) + return(0, datasize("runtime")) + } + object "runtime" { + code { + // Protection against sending Ether + require(iszero(callvalue())) + + // Dispatcher + switch selector() + case 0x70a08231 /* "balanceOf(address)" */ { + returnUint(balanceOf(decodeAsAddress(0))) + } + case 0x18160ddd /* "totalSupply()" */ { + returnUint(totalSupply()) + } + case 0xa9059cbb /* "transfer(address,uint256)" */ { + transfer(decodeAsAddress(0), decodeAsUint(1)) + returnTrue() + } + case 0x23b872dd /* "transferFrom(address,address,uint256)" */ { + transferFrom(decodeAsAddress(0), decodeAsAddress(1), decodeAsUint(2)) + returnTrue() + } + case 0x095ea7b3 /* "approve(address,uint256)" */ { + approve(decodeAsAddress(0), decodeAsUint(1)) + returnTrue() + } + case 0xdd62ed3e /* "allowance(address,address)" */ { + returnUint(allowance(decodeAsAddress(0), decodeAsAddress(1))) + } + case 0x40c10f19 /* "mint(address,uint256)" */ { + mint(decodeAsAddress(0), decodeAsUint(1)) + returnTrue() + } + default { + revert(0, 0) + } + + function mint(account, amount) { + require(calledByOwner()) + + mintTokens(amount) + addToBalance(account, amount) + emitTransfer(0, account, amount) + } + function transfer(to, amount) { + executeTransfer(caller(), to, amount) + } + function approve(spender, amount) { + revertIfZeroAddress(spender) + setAllowance(caller(), spender, amount) + emitApproval(caller(), spender, amount) + } + function transferFrom(from, to, amount) { + decreaseAllowanceBy(from, caller(), amount) + executeTransfer(from, to, amount) + } + + function executeTransfer(from, to, amount) { + revertIfZeroAddress(to) + deductFromBalance(from, amount) + addToBalance(to, amount) + emitTransfer(from, to, amount) + } + + + /* ---------- calldata decoding functions ----------- */ + function selector() -> s { + s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000) + } + + function decodeAsAddress(offset) -> v { + v := decodeAsUint(offset) + if iszero(iszero(and(v, not(0xffffffffffffffffffffffffffffffffffffffff)))) { + revert(0, 0) + } + } + function decodeAsUint(offset) -> v { + let pos := add(4, mul(offset, 0x20)) + if lt(calldatasize(), add(pos, 0x20)) { + revert(0, 0) + } + v := calldataload(pos) + } + /* ---------- calldata encoding functions ---------- */ + function returnUint(v) { + mstore(0, v) + return(0, 0x20) + } + function returnTrue() { + returnUint(1) + } + + /* -------- events ---------- */ + function emitTransfer(from, to, amount) { + let signatureHash := 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + emitEvent(signatureHash, from, to, amount) + } + function emitApproval(from, spender, amount) { + let signatureHash := 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925 + emitEvent(signatureHash, from, spender, amount) + } + function emitEvent(signatureHash, indexed1, indexed2, nonIndexed) { + mstore(0, nonIndexed) + log3(0, 0x20, signatureHash, indexed1, indexed2) + } + + /* -------- storage layout ---------- */ + function ownerPos() -> p { p := 0 } + function totalSupplyPos() -> p { p := 1 } + function accountToStorageOffset(account) -> offset { + offset := add(0x1000, account) + } + function allowanceStorageOffset(account, spender) -> offset { + offset := accountToStorageOffset(account) + mstore(0, offset) + mstore(0x20, spender) + offset := keccak256(0, 0x40) + } + + /* -------- storage access ---------- */ + function owner() -> o { + o := sload(ownerPos()) + } + function totalSupply() -> supply { + supply := sload(totalSupplyPos()) + } + function mintTokens(amount) { + sstore(totalSupplyPos(), safeAdd(totalSupply(), amount)) + } + function balanceOf(account) -> bal { + bal := sload(accountToStorageOffset(account)) + } + function addToBalance(account, amount) { + let offset := accountToStorageOffset(account) + sstore(offset, safeAdd(sload(offset), amount)) + } + function deductFromBalance(account, amount) { + let offset := accountToStorageOffset(account) + let bal := sload(offset) + require(lte(amount, bal)) + sstore(offset, sub(bal, amount)) + } + function allowance(account, spender) -> amount { + amount := sload(allowanceStorageOffset(account, spender)) + } + function setAllowance(account, spender, amount) { + sstore(allowanceStorageOffset(account, spender), amount) + } + function decreaseAllowanceBy(account, spender, amount) { + let offset := allowanceStorageOffset(account, spender) + let currentAllowance := sload(offset) + require(lte(amount, currentAllowance)) + sstore(offset, sub(currentAllowance, amount)) + } + + /* ---------- utility functions ---------- */ + function lte(a, b) -> r { + r := iszero(gt(a, b)) + } + function gte(a, b) -> r { + r := iszero(lt(a, b)) + } + function safeAdd(a, b) -> r { + r := add(a, b) + if or(lt(r, a), lt(r, b)) { revert(0, 0) } + } + function calledByOwner() -> cbo { + cbo := eq(owner(), caller()) + } + function revertIfZeroAddress(addr) { + require(addr) + } + function require(condition) { + if iszero(condition) { revert(0, 0) } + } + } + } + } diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index 62780b19f166..04686ec94567 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -26,9 +26,6 @@ #include #include -#include -#include - #include #include #include diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index 751153b05318..8fb65d1d3620 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -29,9 +29,6 @@ #include #include -#include -#include - #include #include diff --git a/liblangutil/ErrorReporter.cpp b/liblangutil/ErrorReporter.cpp index c6c059bc7f17..d06fbc65baa2 100644 --- a/liblangutil/ErrorReporter.cpp +++ b/liblangutil/ErrorReporter.cpp @@ -28,6 +28,8 @@ using namespace std; using namespace solidity; using namespace solidity::langutil; +ErrorId solidity::langutil::operator"" _error(unsigned long long _error) { return ErrorId{ _error }; } + ErrorReporter& ErrorReporter::operator=(ErrorReporter const& _errorReporter) { if (&_errorReporter == this) @@ -36,30 +38,31 @@ ErrorReporter& ErrorReporter::operator=(ErrorReporter const& _errorReporter) return *this; } - -void ErrorReporter::warning(string const& _description) +void ErrorReporter::warning(ErrorId _error, string const& _description) { - error(Error::Type::Warning, SourceLocation(), _description); + error(_error, Error::Type::Warning, SourceLocation(), _description); } void ErrorReporter::warning( + ErrorId _error, SourceLocation const& _location, string const& _description ) { - error(Error::Type::Warning, _location, _description); + error(_error, Error::Type::Warning, _location, _description); } void ErrorReporter::warning( + ErrorId _error, SourceLocation const& _location, string const& _description, SecondarySourceLocation const& _secondaryLocation ) { - error(Error::Type::Warning, _location, _secondaryLocation, _description); + error(_error, Error::Type::Warning, _location, _secondaryLocation, _description); } -void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, string const& _description) +void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _location, string const& _description) { if (checkForExcessiveErrors(_type)) return; @@ -72,7 +75,7 @@ void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, st m_errorList.push_back(err); } -void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { if (checkForExcessiveErrors(_type)) return; @@ -123,15 +126,15 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type) return false; } -void ErrorReporter::fatalError(Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::fatalError(ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { - error(_type, _location, _secondaryLocation, _description); + error(_error, _type, _location, _secondaryLocation, _description); BOOST_THROW_EXCEPTION(FatalError()); } -void ErrorReporter::fatalError(Error::Type _type, SourceLocation const& _location, string const& _description) +void ErrorReporter::fatalError(ErrorId _error, Error::Type _type, SourceLocation const& _location, string const& _description) { - error(_type, _location, _description); + error(_error, _type, _location, _description); BOOST_THROW_EXCEPTION(FatalError()); } @@ -145,9 +148,10 @@ void ErrorReporter::clear() m_errorList.clear(); } -void ErrorReporter::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::declarationError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { error( + _error, Error::Type::DeclarationError, _location, _secondaryLocation, @@ -155,53 +159,59 @@ void ErrorReporter::declarationError(SourceLocation const& _location, SecondaryS ); } -void ErrorReporter::declarationError(SourceLocation const& _location, string const& _description) +void ErrorReporter::declarationError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::DeclarationError, _location, _description ); } -void ErrorReporter::fatalDeclarationError(SourceLocation const& _location, std::string const& _description) +void ErrorReporter::fatalDeclarationError(ErrorId _error, SourceLocation const& _location, std::string const& _description) { fatalError( + _error, Error::Type::DeclarationError, _location, _description); } -void ErrorReporter::parserError(SourceLocation const& _location, string const& _description) +void ErrorReporter::parserError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::ParserError, _location, _description ); } -void ErrorReporter::fatalParserError(SourceLocation const& _location, string const& _description) +void ErrorReporter::fatalParserError(ErrorId _error, SourceLocation const& _location, string const& _description) { fatalError( + _error, Error::Type::ParserError, _location, _description ); } -void ErrorReporter::syntaxError(SourceLocation const& _location, string const& _description) +void ErrorReporter::syntaxError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::SyntaxError, _location, _description ); } -void ErrorReporter::typeError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::typeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { error( + _error, Error::Type::TypeError, _location, _secondaryLocation, @@ -209,18 +219,21 @@ void ErrorReporter::typeError(SourceLocation const& _location, SecondarySourceLo ); } -void ErrorReporter::typeError(SourceLocation const& _location, string const& _description) +void ErrorReporter::typeError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::TypeError, _location, _description ); } -void ErrorReporter::fatalTypeError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) + +void ErrorReporter::fatalTypeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { fatalError( + _error, Error::Type::TypeError, _location, _secondaryLocation, @@ -228,26 +241,30 @@ void ErrorReporter::fatalTypeError(SourceLocation const& _location, SecondarySou ); } -void ErrorReporter::fatalTypeError(SourceLocation const& _location, string const& _description) +void ErrorReporter::fatalTypeError(ErrorId _error, SourceLocation const& _location, string const& _description) { - fatalError(Error::Type::TypeError, + fatalError( + _error, + Error::Type::TypeError, _location, _description ); } -void ErrorReporter::docstringParsingError(string const& _description) +void ErrorReporter::docstringParsingError(ErrorId _error, string const& _description) { error( + _error, Error::Type::DocstringParsingError, SourceLocation(), _description ); } -void ErrorReporter::docstringParsingError(SourceLocation const& _location, string const& _description) +void ErrorReporter::docstringParsingError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::DocstringParsingError, _location, _description diff --git a/liblangutil/ErrorReporter.h b/liblangutil/ErrorReporter.h index 5aca4beb9232..a52e978afc7c 100644 --- a/liblangutil/ErrorReporter.h +++ b/liblangutil/ErrorReporter.h @@ -33,6 +33,17 @@ namespace solidity::langutil { +/** + * Unique identifiers are used to tag and track individual error cases. + * They are passed as the first parameter of error reporting functions. + * Suffix _error helps to find them in the sources. + * The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error). + * To create a new ID, one can add 0000_error and then run "python ./scripts/correct_error_ids.py" + * from the root of the repo. + */ +struct ErrorId { unsigned long long error = 0; }; +ErrorId operator"" _error(unsigned long long error); + class ErrorReporter { public: @@ -50,64 +61,68 @@ class ErrorReporter m_errorList += _errorList; } - void warning(std::string const& _description); + void warning(ErrorId _error, std::string const& _description); - void warning(SourceLocation const& _location, std::string const& _description); + void warning(ErrorId _error, SourceLocation const& _location, std::string const& _description); void warning( + ErrorId _error, SourceLocation const& _location, std::string const& _description, SecondarySourceLocation const& _secondaryLocation ); void error( + ErrorId _error, Error::Type _type, SourceLocation const& _location, std::string const& _description ); void declarationError( + ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description ); - void declarationError(SourceLocation const& _location, std::string const& _description); + void declarationError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void fatalDeclarationError(SourceLocation const& _location, std::string const& _description); + void fatalDeclarationError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void parserError(SourceLocation const& _location, std::string const& _description); + void parserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void fatalParserError(SourceLocation const& _location, std::string const& _description); + void fatalParserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void syntaxError(SourceLocation const& _location, std::string const& _description); + void syntaxError(ErrorId _error, SourceLocation const& _location, std::string const& _description); void typeError( + ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation = SecondarySourceLocation(), std::string const& _description = std::string() ); - void typeError(SourceLocation const& _location, std::string const& _description); + void typeError(ErrorId _error, SourceLocation const& _location, std::string const& _description); template - void typeErrorConcatenateDescriptions(SourceLocation const& _location, Strings const&... _descriptions) + void typeErrorConcatenateDescriptions(ErrorId _error, SourceLocation const& _location, Strings const&... _descriptions) { - std::initializer_list const descs = {_descriptions...}; + std::initializer_list const descs = { _descriptions... }; solAssert(descs.size() > 0, "Need error descriptions!"); auto filterEmpty = boost::adaptors::filtered([](std::string const& _s) { return !_s.empty(); }); std::string errorStr = util::joinHumanReadable(descs | filterEmpty, " "); - error(Error::Type::TypeError, _location, errorStr); + error(_error, Error::Type::TypeError, _location, errorStr); } - void fatalTypeError(SourceLocation const& _location, std::string const& _description); - void fatalTypeError(SourceLocation const& _location, SecondarySourceLocation const& _secondLocation, std::string const& _description); + void fatalTypeError(ErrorId _error, SourceLocation const& _location, std::string const& _description); + void fatalTypeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondLocation, std::string const& _description); - void docstringParsingError(std::string const& _description); - void docstringParsingError(SourceLocation const& _location, std::string const& _description); + void docstringParsingError(ErrorId _error, std::string const& _description); + void docstringParsingError(ErrorId _error, SourceLocation const& _location, std::string const& _description); ErrorList const& errors() const; @@ -119,23 +134,32 @@ class ErrorReporter return m_errorCount > 0; } + /// @returns the number of errors (ignores warnings). + unsigned errorCount() const + { + return m_errorCount; + } + // @returns true if the maximum error count has been reached. bool hasExcessiveErrors() const; private: void error( + ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description = std::string()); void fatalError( + ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description = std::string()); void fatalError( + ErrorId _error, Error::Type _type, SourceLocation const& _location = SourceLocation(), std::string const& _description = std::string()); diff --git a/liblangutil/ParserBase.cpp b/liblangutil/ParserBase.cpp index 747cb37cfdd8..be8ec3eb9ab1 100644 --- a/liblangutil/ParserBase.cpp +++ b/liblangutil/ParserBase.cpp @@ -77,9 +77,9 @@ void ParserBase::expectToken(Token _value, bool _advance) { string const expectedToken = ParserBase::tokenName(_value); if (m_parserErrorRecovery) - parserError("Expected " + expectedToken + " but got " + tokenName(tok)); + parserError(6635_error, "Expected " + expectedToken + " but got " + tokenName(tok)); else - fatalParserError("Expected " + expectedToken + " but got " + tokenName(tok)); + fatalParserError(2314_error, "Expected " + expectedToken + " but got " + tokenName(tok)); // Do not advance so that recovery can sync or make use of the current token. // This is especially useful if the expected token // is the only one that is missing and is at the end of a construct. @@ -108,21 +108,21 @@ void ParserBase::expectTokenOrConsumeUntil(Token _value, string const& _currentN // rollback to where the token started, and raise exception to be caught at a higher level. m_scanner->setPosition(startPosition); m_inParserRecovery = true; - fatalParserError(errorLoc, msg); + fatalParserError(1957_error, errorLoc, msg); } else { if (m_inParserRecovery) - parserWarning("Recovered in " + _currentNodeName + " at " + expectedToken + "."); + parserWarning(3796_error, "Recovered in " + _currentNodeName + " at " + expectedToken + "."); else - parserError(errorLoc, msg + "Recovered at next " + expectedToken); + parserError(1054_error, errorLoc, msg + "Recovered at next " + expectedToken); m_inParserRecovery = false; } } else if (m_inParserRecovery) { string expectedToken = ParserBase::tokenName(_value); - parserWarning("Recovered in " + _currentNodeName + " at " + expectedToken + "."); + parserWarning(3347_error, "Recovered in " + _currentNodeName + " at " + expectedToken + "."); m_inParserRecovery = false; } @@ -134,7 +134,7 @@ void ParserBase::increaseRecursionDepth() { m_recursionDepth++; if (m_recursionDepth >= 1200) - fatalParserError("Maximum recursion depth reached during parsing."); + fatalParserError(7319_error, "Maximum recursion depth reached during parsing."); } void ParserBase::decreaseRecursionDepth() @@ -143,27 +143,32 @@ void ParserBase::decreaseRecursionDepth() m_recursionDepth--; } -void ParserBase::parserWarning(string const& _description) +void ParserBase::parserWarning(ErrorId _error, string const& _description) { - m_errorReporter.warning(currentLocation(), _description); + m_errorReporter.warning(_error, currentLocation(), _description); } -void ParserBase::parserError(SourceLocation const& _location, string const& _description) +void ParserBase::parserWarning(ErrorId _error, SourceLocation const& _location, string const& _description) { - m_errorReporter.parserError(_location, _description); + m_errorReporter.warning(_error, _location, _description); } -void ParserBase::parserError(string const& _description) +void ParserBase::parserError(ErrorId _error, SourceLocation const& _location, string const& _description) { - parserError(currentLocation(), _description); + m_errorReporter.parserError(_error, _location, _description); } -void ParserBase::fatalParserError(string const& _description) +void ParserBase::parserError(ErrorId _error, string const& _description) { - fatalParserError(currentLocation(), _description); + parserError(_error, currentLocation(), _description); } -void ParserBase::fatalParserError(SourceLocation const& _location, string const& _description) +void ParserBase::fatalParserError(ErrorId _error, string const& _description) { - m_errorReporter.fatalParserError(_location, _description); + fatalParserError(_error, currentLocation(), _description); +} + +void ParserBase::fatalParserError(ErrorId _error, SourceLocation const& _location, string const& _description) +{ + m_errorReporter.fatalParserError(_error, _location, _description); } diff --git a/liblangutil/ParserBase.h b/liblangutil/ParserBase.h index 575a049e2b7a..bb4123b9f58c 100644 --- a/liblangutil/ParserBase.h +++ b/liblangutil/ParserBase.h @@ -32,6 +32,7 @@ namespace solidity::langutil class ErrorReporter; class Scanner; +struct ErrorId; class ParserBase { @@ -88,17 +89,18 @@ class ParserBase /// Creates a @ref ParserError and annotates it with the current position and the /// given @a _description. - void parserError(std::string const& _description); - void parserError(SourceLocation const& _location, std::string const& _description); + void parserError(ErrorId _error, std::string const& _description); + void parserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); /// Creates a @ref ParserWarning and annotates it with the current position and the /// given @a _description. - void parserWarning(std::string const& _description); + void parserWarning(ErrorId _error, std::string const& _description); + void parserWarning(ErrorId _error, SourceLocation const& _location, std::string const& _description); /// Creates a @ref ParserError and annotates it with the current position and the /// given @a _description. Throws the FatalError. - void fatalParserError(std::string const& _description); - void fatalParserError(SourceLocation const& _location, std::string const& _description); + void fatalParserError(ErrorId _error, std::string const& _description); + void fatalParserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); std::shared_ptr m_scanner; /// The reference to the list of errors and warning to add errors/warnings during parsing diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index fe1bbad7aeac..96ccff9e4a06 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -166,7 +166,7 @@ if (NOT (${Z3_FOUND} OR ${CVC4_FOUND})) endif() add_library(solidity ${sources} ${z3_SRCS} ${cvc4_SRCS}) -target_link_libraries(solidity PUBLIC yul evmasm langutil solutil Boost::boost Boost::filesystem Boost::system) +target_link_libraries(solidity PUBLIC yul evmasm langutil solutil Boost::boost) if (${Z3_FOUND}) target_link_libraries(solidity PUBLIC z3::libz3) diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index d48d640ce1b0..4bd8b1389865 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -29,6 +29,7 @@ using namespace std; using namespace solidity; using namespace solidity::frontend; +using namespace solidity::langutil; void ConstantEvaluator::endVisit(UnaryOperation const& _operation) { @@ -46,6 +47,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation) TypePointer commonType = left->binaryOperatorResult(_operation.getOperator(), right); if (!commonType) m_errorReporter.fatalTypeError( + 6020_error, _operation.location(), "Operator " + string(TokenTraits::toString(_operation.getOperator())) + @@ -82,7 +84,7 @@ void ConstantEvaluator::endVisit(Identifier const& _identifier) else if (!m_types->count(value.get())) { if (m_depth > 32) - m_errorReporter.fatalTypeError(_identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted)."); + m_errorReporter.fatalTypeError(5210_error, _identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted)."); ConstantEvaluator(m_errorReporter, m_depth + 1, m_types).evaluate(*value); } diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 18051f99bb49..cb8694537338 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -26,7 +26,6 @@ #include #include #include -#include using namespace std; @@ -78,6 +77,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co { if (constructor) m_errorReporter.declarationError( + 7997_error, function->location(), SecondarySourceLocation().append("Another declaration is here:", constructor->location()), "More than one constructor defined." @@ -88,6 +88,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co { if (fallback) m_errorReporter.declarationError( + 7301_error, function->location(), SecondarySourceLocation().append("Another declaration is here:", fallback->location()), "Only one fallback function is allowed." @@ -98,6 +99,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co { if (receive) m_errorReporter.declarationError( + 4046_error, function->location(), SecondarySourceLocation().append("Another declaration is here:", receive->location()), "Only one receive function is allowed." @@ -110,7 +112,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co functions[function->name()].push_back(function); } - findDuplicateDefinitions(functions, "Function with same name and arguments defined twice."); + findDuplicateDefinitions(functions); } void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract) @@ -121,11 +123,11 @@ void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contr for (EventDefinition const* event: _contract.events()) events[event->name()].push_back(event); - findDuplicateDefinitions(events, "Event with same name and arguments defined twice."); + findDuplicateDefinitions(events); } template -void ContractLevelChecker::findDuplicateDefinitions(map> const& _definitions, string _message) +void ContractLevelChecker::findDuplicateDefinitions(map> const& _definitions) { for (auto const& it: _definitions) { @@ -144,12 +146,27 @@ void ContractLevelChecker::findDuplicateDefinitions(map> const if (ssl.infos.size() > 0) { - ssl.limitSize(_message); + ErrorId error; + string message; + if constexpr (is_same_v) + { + error = 1686_error; + message = "Function with same name and arguments defined twice."; + } + else + { + static_assert(is_same_v, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\""); + error = 5883_error; + message = "Event with same name and arguments defined twice."; + } + + ssl.limitSize(message); m_errorReporter.declarationError( + error, overloads[i]->location(), ssl, - _message + message ); } } @@ -197,9 +214,9 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c if (_contract.abstract()) { if (_contract.contractKind() == ContractKind::Interface) - m_errorReporter.typeError(_contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly."); + m_errorReporter.typeError(9348_error, _contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly."); else if (_contract.contractKind() == ContractKind::Library) - m_errorReporter.typeError(_contract.location(), "Libraries cannot be abstract."); + m_errorReporter.typeError(9571_error, _contract.location(), "Libraries cannot be abstract."); else solAssert(_contract.contractKind() == ContractKind::Contract, ""); } @@ -215,10 +232,12 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c SecondarySourceLocation ssl; for (auto declaration: _contract.annotation().unimplementedDeclarations) ssl.append("Missing implementation: ", declaration->location()); - m_errorReporter.typeError(_contract.location(), ssl, - "Contract \"" + _contract.annotation().canonicalName - + "\" should be marked as abstract."); - + m_errorReporter.typeError( + 3656_error, + _contract.location(), + ssl, + "Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract." + ); } } @@ -243,6 +262,7 @@ void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition cons } else m_errorReporter.declarationError( + 1563_error, modifier->location(), "Modifier-style base constructor call without arguments." ); @@ -304,6 +324,7 @@ void ContractLevelChecker::annotateBaseConstructorArguments( } m_errorReporter.declarationError( + 3364_error, *mainLocation, ssl, "Base constructor arguments given twice." @@ -343,6 +364,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c for (size_t j = i + 1; j < it.second.size(); ++j) if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second)) m_errorReporter.typeError( + 9914_error, it.second[j].first->location(), "Function overload clash during conversion to external types for arguments." ); @@ -356,6 +378,7 @@ void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contra util::FixedHash<4> const& hash = it.first; if (hashes.count(hash)) m_errorReporter.typeError( + 1860_error, _contract.location(), string("Function signature hash collision for ") + it.second->externalSignature() ); @@ -369,11 +392,11 @@ void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _c return; if (!_contract.baseContracts().empty()) - m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit."); + m_errorReporter.typeError(9469_error, _contract.location(), "Library is not allowed to inherit."); for (auto const& var: _contract.stateVariables()) if (!var->isConstant()) - m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables"); + m_errorReporter.typeError(9957_error, var->location(), "Library cannot have non-constant state variables"); } void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _contract) @@ -412,6 +435,7 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _ if (!errors.infos.empty()) m_errorReporter.fatalTypeError( + 6594_error, _contract.location(), errors, std::string("Contract \"") + @@ -428,6 +452,7 @@ void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition if (auto const* fallback = _contract.fallbackFunction()) if (fallback->isPayable() && !_contract.interfaceFunctionList().empty() && !_contract.receiveFunction()) m_errorReporter.warning( + 3628_error, _contract.location(), "This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.", SecondarySourceLocation{}.append("The payable fallback function is defined here.", fallback->location()) diff --git a/libsolidity/analysis/ContractLevelChecker.h b/libsolidity/analysis/ContractLevelChecker.h index 736b3d3d7a29..e40cb8b0d5b8 100644 --- a/libsolidity/analysis/ContractLevelChecker.h +++ b/libsolidity/analysis/ContractLevelChecker.h @@ -60,7 +60,7 @@ class ContractLevelChecker void checkDuplicateFunctions(ContractDefinition const& _contract); void checkDuplicateEvents(ContractDefinition const& _contract); template - void findDuplicateDefinitions(std::map> const& _definitions, std::string _message); + void findDuplicateDefinitions(std::map> const& _definitions); /// Checks for unimplemented functions and modifiers. void checkAbstractDefinitions(ContractDefinition const& _contract); /// Checks that the base constructor arguments are properly provided. diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp index 1a001eb1e92e..84979082fc2b 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.cpp +++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp @@ -136,6 +136,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod ssl.append("The variable was declared here.", variableOccurrence->declaration().location()); m_errorReporter.typeError( + 3464_error, variableOccurrence->occurrence() ? *variableOccurrence->occurrence() : variableOccurrence->declaration().location(), @@ -176,6 +177,6 @@ void ControlFlowAnalyzer::checkUnreachable(CFGNode const* _entry, CFGNode const* // Extend the location, as long as the next location overlaps (unreachable is sorted). for (; it != unreachable.end() && it->start <= location.end; ++it) location.end = std::max(location.end, it->end); - m_errorReporter.warning(location, "Unreachable code."); + m_errorReporter.warning(5740_error, location, "Unreachable code."); } } diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp index 4cb096ae04c0..fb5fc1be0221 100644 --- a/libsolidity/analysis/ControlFlowGraph.cpp +++ b/libsolidity/analysis/ControlFlowGraph.cpp @@ -18,7 +18,6 @@ #include #include -#include #include using namespace std; diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 0c53732d614d..a06679b973c0 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -188,12 +188,14 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping) { if (contractType->contractDefinition().isLibrary()) m_errorReporter.fatalTypeError( + 1665_error, typeName->location(), "Library types cannot be used as mapping keys." ); } else if (typeName->annotation().type->category() != Type::Category::Enum) m_errorReporter.fatalTypeError( + 7804_error, typeName->location(), "Only elementary types, contract types or enums are allowed as mapping keys." ); @@ -253,9 +255,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) return; if (_variable.isConstant() && !_variable.isStateVariable()) - m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables."); + m_errorReporter.declarationError(1788_error, _variable.location(), "The \"constant\" keyword can only be used for state variables."); if (_variable.immutable() && !_variable.isStateVariable()) - m_errorReporter.declarationError(_variable.location(), "The \"immutable\" keyword can only be used for state variables."); + m_errorReporter.declarationError(8297_error, _variable.location(), "The \"immutable\" keyword can only be used for state variables."); if (!_variable.typeName()) { @@ -359,24 +361,22 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) void DeclarationTypeChecker::typeError(SourceLocation const& _location, string const& _description) { - m_errorOccurred = true; - m_errorReporter.typeError(_location, _description); + m_errorReporter.typeError(2311_error, _location, _description); } void DeclarationTypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description) { - m_errorOccurred = true; - m_errorReporter.fatalTypeError(_location, _description); + m_errorReporter.fatalTypeError(5651_error, _location, _description); } void DeclarationTypeChecker::fatalDeclarationError(SourceLocation const& _location, string const& _description) { - m_errorOccurred = true; - m_errorReporter.fatalDeclarationError(_location, _description); + m_errorReporter.fatalDeclarationError(2046_error, _location, _description); } bool DeclarationTypeChecker::check(ASTNode const& _node) { + unsigned errorCount = m_errorReporter.errorCount(); _node.accept(*this); - return !m_errorOccurred; + return m_errorReporter.errorCount() == errorCount; } diff --git a/libsolidity/analysis/DeclarationTypeChecker.h b/libsolidity/analysis/DeclarationTypeChecker.h index b704c4fd203d..e5407599828a 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.h +++ b/libsolidity/analysis/DeclarationTypeChecker.h @@ -69,7 +69,6 @@ class DeclarationTypeChecker: private ASTConstVisitor void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description); langutil::ErrorReporter& m_errorReporter; - bool m_errorOccurred = false; langutil::EVMVersion m_evmVersion; bool m_insideFunctionType = false; bool m_recursiveStructSeen = false; diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index ee0a39163704..53edc8cdf055 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -173,5 +173,5 @@ void DocStringAnalyser::parseDocStrings( void DocStringAnalyser::appendError(SourceLocation const& _location, string const& _description) { m_errorOccured = true; - m_errorReporter.docstringParsingError(_location, _description); + m_errorReporter.docstringParsingError(7816_error, _location, _description); } diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index a0764edba7b7..53020afce97d 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -100,11 +100,13 @@ inline vector> constructMagicVariable magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), + // Accepts a MagicType that can be any contract type or an Integer type and returns a + // MagicType. The TypeChecker handles the correctness of the input and output types. magicVarDecl("type", TypeProvider::function( - strings{"address"} /* accepts any contract type, handled by the type checker */, - strings{} /* returns a MagicType, handled by the type checker */, + strings{}, + strings{}, FunctionType::Kind::MetaType, - false, + true, StateMutability::Pure )), }; @@ -123,7 +125,7 @@ vector GlobalContext::declarations() const { vector declarations; declarations.reserve(m_magicVariables.size()); - for (ASTPointer const& variable: m_magicVariables) + for (ASTPointer const& variable: m_magicVariables) declarations.push_back(variable.get()); return declarations; } diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index 598f43e50830..e4fcfadcf366 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -22,6 +22,7 @@ #include using namespace solidity::frontend; +using namespace solidity::langutil; void ImmutableValidator::analyze() { @@ -42,7 +43,7 @@ void ImmutableValidator::analyze() visitCallableIfNew(*contract->constructor()); for (ContractDefinition const* contract: linearizedContracts) - for (std::shared_ptr const inheritSpec: contract->baseContracts()) + for (std::shared_ptr const& inheritSpec: contract->baseContracts()) if (auto args = inheritSpec->arguments()) ASTNode::listAccept(*args, *this); @@ -165,33 +166,39 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va { if (!m_currentConstructor) m_errorReporter.typeError( + 1581_error, _expression.location(), "Immutable variables can only be initialized inline or assigned directly in the constructor." ); else if (m_currentConstructor->annotation().contract->id() != _variableReference.annotation().contract->id()) m_errorReporter.typeError( + 7484_error, _expression.location(), "Immutable variables must be initialized in the constructor of the contract they are defined in." ); else if (m_inLoop) m_errorReporter.typeError( + 6672_error, _expression.location(), "Immutable variables can only be initialized once, not in a while statement." ); else if (m_inBranch) m_errorReporter.typeError( + 4599_error, _expression.location(), "Immutable variables must be initialized unconditionally, not in an if statement." ); if (!m_initializedStateVariables.emplace(&_variableReference).second) m_errorReporter.typeError( + 1574_error, _expression.location(), "Immutable state variable already initialized." ); } else if (m_inConstructionContext) m_errorReporter.typeError( + 7733_error, _expression.location(), "Immutable variables cannot be read during contract creation time, which means " "they cannot be read in the constructor or any function or modifier called from it." @@ -205,6 +212,7 @@ void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::Source if (varDecl->immutable()) if (!util::contains(m_initializedStateVariables, varDecl)) m_errorReporter.typeError( + 2658_error, _location, solidity::langutil::SecondarySourceLocation().append("Not initialized: ", varDecl->location()), "Construction control flow ends without initializing all immutable state variables." diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 65831ec868e4..87482b78c67d 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -80,6 +80,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, maplocation(), "Import \"" + path + "\" (referenced as \"" + imp->path() + "\") not found." ); @@ -95,6 +96,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, maplocation(), "Declaration \"" + alias.symbol->name() + @@ -208,6 +210,7 @@ void NameAndTypeResolver::warnVariablesNamedLikeInstructions() // Don't warn the user for what the user did not. continue; m_errorReporter.warning( + 8261_error, declaration->location(), "Variable is shadowed in inline assembly by an instruction of the same name" ); @@ -326,6 +329,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) } m_errorReporter.declarationError( + 9097_error, secondDeclarationLocation, SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation), "Identifier already declared." @@ -343,19 +347,19 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) UserDefinedTypeName const& baseName = baseSpecifier->name(); auto base = dynamic_cast(baseName.annotation().referencedDeclaration); if (!base) - m_errorReporter.fatalTypeError(baseName.location(), "Contract expected."); + m_errorReporter.fatalTypeError(8758_error, baseName.location(), "Contract expected."); // "push_front" has the effect that bases mentioned later can overwrite members of bases // mentioned earlier input.back().push_front(base); vector const& basesBases = base->annotation().linearizedBaseContracts; if (basesBases.empty()) - m_errorReporter.fatalTypeError(baseName.location(), "Definition of base has to precede definition of derived contract"); + m_errorReporter.fatalTypeError(2449_error, baseName.location(), "Definition of base has to precede definition of derived contract"); input.push_front(list(basesBases.begin(), basesBases.end())); } input.back().push_front(&_contract); vector result = cThreeMerge(input); if (result.empty()) - m_errorReporter.fatalTypeError(_contract.location(), "Linearization of inheritance graph impossible"); + m_errorReporter.fatalTypeError(5005_error, _contract.location(), "Linearization of inheritance graph impossible"); _contract.annotation().linearizedBaseContracts = result; _contract.annotation().contractDependencies.insert(result.begin() + 1, result.end()); } @@ -476,6 +480,7 @@ bool DeclarationRegistrationHelper::registerDeclaration( } _errorReporter.declarationError( + 2333_error, secondDeclarationLocation, SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation), "Identifier already declared." @@ -486,6 +491,7 @@ bool DeclarationRegistrationHelper::registerDeclaration( { if (dynamic_cast(shadowedDeclaration)) _errorReporter.warning( + 2319_error, *_errorLocation, "This declaration shadows a builtin symbol." ); @@ -493,6 +499,7 @@ bool DeclarationRegistrationHelper::registerDeclaration( { auto shadowedLocation = shadowedDeclaration->location(); _errorReporter.warning( + 2519_error, _declaration.location(), "This declaration shadows an existing declaration.", SecondarySourceLocation().append("The shadowed declaration is here:", shadowedLocation) diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 91b45d33c184..4cf2ff8f41b0 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -27,7 +27,6 @@ #include #include -#include #include @@ -461,6 +460,7 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract) { if (contains_if(inheritedFuncs, MatchByName{modifier->name()})) m_errorReporter.typeError( + 5631_error, modifier->location(), "Override changes function or public state variable to modifier." ); @@ -474,7 +474,7 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract) continue; if (contains_if(inheritedMods, MatchByName{function->name()})) - m_errorReporter.typeError(function->location(), "Override changes modifier to function."); + m_errorReporter.typeError(1469_error, function->location(), "Override changes modifier to function."); checkOverrideList(OverrideProxy{function}, inheritedFuncs); } @@ -484,7 +484,7 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract) continue; if (contains_if(inheritedMods, MatchByName{stateVar->name()})) - m_errorReporter.typeError(stateVar->location(), "Override changes modifier to public state variable."); + m_errorReporter.typeError(1456_error, stateVar->location(), "Override changes modifier to public state variable."); checkOverrideList(OverrideProxy{stateVar}, inheritedFuncs); } @@ -500,17 +500,19 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr if (_overriding.isModifier() && *_overriding.modifierType() != *_super.modifierType()) m_errorReporter.typeError( + 1078_error, _overriding.location(), "Override changes modifier signature." ); if (!_overriding.overrides()) - overrideError(_overriding, _super, "Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier."); + overrideError(_overriding, _super, 9456_error, "Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier."); if (_super.isVariable()) overrideError( _super, _overriding, + 1452_error, "Cannot override public state variable.", "Overriding " + _overriding.astNodeName() + " is here:" ); @@ -518,6 +520,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr overrideError( _super, _overriding, + 4334_error, "Trying to override non-virtual " + _super.astNodeName() + ". Did you forget to add \"virtual\"?", "Overriding " + _overriding.astNodeName() + " is here:" ); @@ -525,7 +528,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr if (_overriding.isVariable()) { if (_super.visibility() != Visibility::External) - overrideError(_overriding, _super, "Public state variables can only override functions with external visibility."); + overrideError(_overriding, _super, 5225_error, "Public state variables can only override functions with external visibility."); solAssert(_overriding.visibility() == Visibility::External, ""); } else if (_overriding.visibility() != _super.visibility()) @@ -536,7 +539,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr _super.visibility() == Visibility::External && _overriding.visibility() == Visibility::Public )) - overrideError(_overriding, _super, "Overriding " + _overriding.astNodeName() + " visibility differs."); + overrideError(_overriding, _super, 9098_error, "Overriding " + _overriding.astNodeName() + " visibility differs."); } if (_super.isFunction()) @@ -547,7 +550,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!"); if (!functionType->hasEqualReturnTypes(*superType)) - overrideError(_overriding, _super, "Overriding " + _overriding.astNodeName() + " return types differ."); + overrideError(_overriding, _super, 4822_error, "Overriding " + _overriding.astNodeName() + " return types differ."); // This is only relevant for a function overriding a function. if (_overriding.isFunction()) @@ -556,6 +559,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr overrideError( _overriding, _super, + 2837_error, "Overriding function changes state mutability from \"" + stateMutabilityToString(_super.stateMutability()) + "\" to \"" + @@ -567,6 +571,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr overrideError( _overriding, _super, + 4593_error, "Overriding an implemented function with an unimplemented function is not allowed." ); } @@ -576,6 +581,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr void OverrideChecker::overrideListError( OverrideProxy const& _item, set _secondary, + ErrorId _error, string const& _message1, string const& _message2 ) @@ -593,6 +599,7 @@ void OverrideChecker::overrideListError( contractSingularPlural = "contracts "; m_errorReporter.typeError( + _error, _item.overrides() ? _item.overrides()->location() : _item.location(), ssl, _message1 + @@ -603,9 +610,10 @@ void OverrideChecker::overrideListError( ); } -void OverrideChecker::overrideError(Declaration const& _overriding, Declaration const& _super, string const& _message, string const& _secondaryMsg) +void OverrideChecker::overrideError(Declaration const& _overriding, Declaration const& _super, ErrorId _error, string const& _message, string const& _secondaryMsg) { m_errorReporter.typeError( + _error, _overriding.location(), SecondarySourceLocation().append(_secondaryMsg, _super.location()), _message @@ -613,9 +621,10 @@ void OverrideChecker::overrideError(Declaration const& _overriding, Declaration } -void OverrideChecker::overrideError(OverrideProxy const& _overriding, OverrideProxy const& _super, string const& _message, string const& _secondaryMsg) +void OverrideChecker::overrideError(OverrideProxy const& _overriding, OverrideProxy const& _super, ErrorId _error, string const& _message, string const& _secondaryMsg) { m_errorReporter.typeError( + _error, _overriding.location(), SecondarySourceLocation().append(_secondaryMsg, _super.location()), _message @@ -718,7 +727,7 @@ void OverrideChecker::checkAmbiguousOverridesInternal(set _baseCa " Since one of the bases defines a public state variable which cannot be overridden, " "you have to change the inheritance layout or the names of the functions."; - m_errorReporter.typeError(_location, ssl, message); + m_errorReporter.typeError(6480_error, _location, ssl, message); } set OverrideChecker::resolveOverrideList(OverrideSpecifier const& _overrides) const @@ -766,13 +775,14 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign SecondarySourceLocation ssl; ssl.append("First occurrence here: ", list[i-1]->location()); m_errorReporter.typeError( + 4520_error, list[i]->location(), ssl, - "Duplicate contract \"" + - joinHumanReadable(list[i]->namePath(), ".") + - "\" found in override list of \"" + - _item.name() + - "\"." + "Duplicate contract \"" + + joinHumanReadable(list[i]->namePath(), ".") + + "\" found in override list of \"" + + _item.name() + + "\"." ); } } @@ -791,6 +801,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign if (_item.overrides() && expectedContracts.empty()) m_errorReporter.typeError( + 7792_error, _item.overrides()->location(), _item.astNodeNameCapitalized() + " has override specified but does not override anything." ); @@ -804,6 +815,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign overrideListError( _item, missingContracts, + 4327_error, _item.astNodeNameCapitalized() + " needs to specify overridden ", "" ); @@ -813,6 +825,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign overrideListError( _item, surplusContracts, + 2353_error, "Invalid ", "specified in override list: " ); diff --git a/libsolidity/analysis/OverrideChecker.h b/libsolidity/analysis/OverrideChecker.h index 9d77760282a4..d47b89f3dd4f 100644 --- a/libsolidity/analysis/OverrideChecker.h +++ b/libsolidity/analysis/OverrideChecker.h @@ -32,6 +32,7 @@ namespace solidity::langutil { class ErrorReporter; +struct ErrorId; struct SourceLocation; } @@ -160,18 +161,21 @@ class OverrideChecker void overrideListError( OverrideProxy const& _item, std::set _secondary, + langutil::ErrorId _error, std::string const& _message1, std::string const& _message2 ); void overrideError( Declaration const& _overriding, Declaration const& _super, + langutil::ErrorId _error, std::string const& _message, std::string const& _secondaryMsg = "Overridden function is here:" ); void overrideError( OverrideProxy const& _overriding, OverrideProxy const& _super, + langutil::ErrorId _error, std::string const& _message, std::string const& _secondaryMsg = "Overridden function is here:" ); diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index 62317587ab34..1b5b5b7c351c 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -122,6 +122,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker for (auto declaration: m_constVariables) if (auto identifier = findCycle(*declaration)) m_errorReporter.typeError( + 6161_error, declaration->location(), "The value of the constant " + declaration->name() + " has a cyclic dependency via " + identifier->name() + "." @@ -165,7 +166,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker auto visitor = [&](VariableDeclaration const& _variable, util::CycleDetector& _cycleDetector, size_t _depth) { if (_depth >= 256) - m_errorReporter.fatalDeclarationError(_variable.location(), "Variable definition exhausting cyclic dependency validator."); + m_errorReporter.fatalDeclarationError(7380_error, _variable.location(), "Variable definition exhausting cyclic dependency validator."); // Iterating through the dependencies needs to be deterministic and thus cannot // depend on the memory layout. @@ -209,6 +210,7 @@ struct OverrideSpecifierChecker: public PostTypeChecker::Checker TypeType const* actualTypeType = dynamic_cast(decl->type()); m_errorReporter.typeError( + 9301_error, override->location(), "Expected contract but got " + actualTypeType->actualType()->toString(true) + @@ -243,6 +245,7 @@ struct ModifierContextChecker: public PostTypeChecker::Checker if (ModifierType const* type = dynamic_cast(_identifier.annotation().type)) { m_errorReporter.typeError( + 3112_error, _identifier.location(), "Modifier can only be referenced in function headers." ); @@ -280,6 +283,7 @@ struct EventOutsideEmitChecker: public PostTypeChecker::Checker // Check for event outside of emit statement if (!m_insideEmitStatement && functionType->kind() == FunctionType::Kind::Event) m_errorReporter.typeError( + 3132_error, _functionCall.location(), "Event invocations have to be prefixed by \"emit\"." ); @@ -308,7 +312,7 @@ struct NoVariablesInInterfaceChecker: public PostTypeChecker::Checker && !_variable.isCallableOrCatchParameter() && !m_insideStruct ) - m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces."); + m_errorReporter.typeError(8274_error, _variable.location(), "Variables cannot be declared in interfaces."); return true; } diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f72253c1f622..3415dee229c9 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -268,19 +268,19 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl) void ReferencesResolver::declarationError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.declarationError(_location, _description); + m_errorReporter.declarationError(8532_error, _location, _description); } void ReferencesResolver::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _ssl, string const& _description) { m_errorOccurred = true; - m_errorReporter.declarationError(_location, _ssl, _description); + m_errorReporter.declarationError(3881_error, _location, _ssl, _description); } void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.fatalDeclarationError(_location, _description); + m_errorReporter.fatalDeclarationError(6546_error, _location, _description); } } diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index c53bc03fae14..3cbfa4db4c8d 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -120,13 +120,14 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&) { if (var.first.second->isCallableOrCatchParameter()) m_errorReporter.warning( + 5667_error, var.first.second->location(), "Unused " + string(var.first.second->isTryCatchParameter() ? "try/catch" : "function") + " parameter. Remove or comment out the variable name to silence this warning." ); else - m_errorReporter.warning(var.first.second->location(), "Unused local variable."); + m_errorReporter.warning(2072_error, var.first.second->location(), "Unused local variable."); } m_localVarUseCount.clear(); m_constructor = false; @@ -159,6 +160,7 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable) set structsSeen; if (structureSizeEstimate(*_variable.type(), structsSeen) >= bigint(1) << 64) m_errorReporter.warning( + 3408_error, _variable.location(), "Variable covers a large part of storage and thus makes collisions likely. " "Either use mappings or dynamic arrays and allow their size to be increased only " @@ -183,6 +185,7 @@ bool StaticAnalyzer::visit(ExpressionStatement const& _statement) { if (_statement.expression().annotation().isPure) m_errorReporter.warning( + 6133_error, _statement.location(), "Statement has no effect." ); @@ -196,11 +199,13 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) { if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "gas") m_errorReporter.typeError( + 1400_error, _memberAccess.location(), "\"msg.gas\" has been deprecated in favor of \"gasleft()\"" ); else if (type->kind() == MagicType::Kind::Block && _memberAccess.memberName() == "blockhash") m_errorReporter.typeError( + 8113_error, _memberAccess.location(), "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\"" ); @@ -211,6 +216,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) ContractType const& contract = dynamic_cast(*type->typeArgument()); if (m_constructorUsesAssembly->check(contract.contractDefinition())) m_errorReporter.warning( + 6417_error, _memberAccess.location(), "The constructor of the contract (or its base) uses inline assembly. " "Because of that, it might be that the deployed bytecode is different from type(...).runtimeCode." @@ -222,6 +228,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) if (auto const* type = dynamic_cast(_memberAccess.annotation().type)) if (type->kind() == FunctionType::Kind::BareCallCode) m_errorReporter.typeError( + 2256_error, _memberAccess.location(), "\"callcode\" has been deprecated in favour of \"delegatecall\"." ); @@ -235,6 +242,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) { if (id->name() == "this") m_errorReporter.warning( + 5805_error, id->location(), "\"this\" used in constructor. " "Note that external functions of a contract " @@ -285,6 +293,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation) )) if (rhs->isZero()) m_errorReporter.typeError( + 1211_error, _operation.location(), (_operation.getOperator() == Token::Div) ? "Division by zero." : "Modulo zero." ); @@ -307,6 +316,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall) )) if (lastArg->isZero()) m_errorReporter.typeError( + 4195_error, _functionCall.location(), "Arithmetic modulo zero." ); @@ -317,6 +327,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall) functionType->declaration().scope() == m_currentContract ) m_errorReporter.typeError( + 6700_error, _functionCall.location(), SecondarySourceLocation().append( "The function declaration is here:", diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index c9ad29d332b8..86204e88e8c4 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -69,7 +68,7 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit) string(";\""); // when reporting the warning, print the source name only - m_errorReporter.warning({-1, -1, _sourceUnit.location().source}, errorString); + m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().source}, errorString); } m_sourceUnit = nullptr; } @@ -79,18 +78,20 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) solAssert(!_pragma.tokens().empty(), ""); solAssert(_pragma.tokens().size() == _pragma.literals().size(), ""); if (_pragma.tokens()[0] != Token::Identifier) - m_errorReporter.syntaxError(_pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\""); + m_errorReporter.syntaxError(5226_error, _pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\""); else if (_pragma.literals()[0] == "experimental") { solAssert(m_sourceUnit, ""); vector literals(_pragma.literals().begin() + 1, _pragma.literals().end()); if (literals.empty()) m_errorReporter.syntaxError( + 9679_error, _pragma.location(), "Experimental feature name is missing." ); else if (literals.size() > 1) m_errorReporter.syntaxError( + 6022_error, _pragma.location(), "Stray arguments." ); @@ -98,17 +99,17 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) { string const literal = literals[0]; if (literal.empty()) - m_errorReporter.syntaxError(_pragma.location(), "Empty experimental feature name is invalid."); + m_errorReporter.syntaxError(3250_error, _pragma.location(), "Empty experimental feature name is invalid."); else if (!ExperimentalFeatureNames.count(literal)) - m_errorReporter.syntaxError(_pragma.location(), "Unsupported experimental feature name."); + m_errorReporter.syntaxError(8491_error, _pragma.location(), "Unsupported experimental feature name."); else if (m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeatureNames.at(literal))) - m_errorReporter.syntaxError(_pragma.location(), "Duplicate experimental feature name."); + m_errorReporter.syntaxError(1231_error, _pragma.location(), "Duplicate experimental feature name."); else { auto feature = ExperimentalFeatureNames.at(literal); m_sourceUnit->annotation().experimentalFeatures.insert(feature); if (!ExperimentalFeatureWithoutWarning.count(feature)) - m_errorReporter.warning(_pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments."); + m_errorReporter.warning(2264_error, _pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments."); } } } @@ -121,15 +122,16 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) static SemVerVersion const currentVersion{string(VersionString)}; if (!matchExpression.matches(currentVersion)) m_errorReporter.syntaxError( + 3997_error, _pragma.location(), "Source file requires different compiler version (current compiler is " + - string(VersionString) + " - note that nightly builds are considered to be " + string(VersionString) + ") - note that nightly builds are considered to be " "strictly less than the released version" ); m_versionPragmaFound = true; } else - m_errorReporter.syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); + m_errorReporter.syntaxError(4936_error, _pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); return true; } @@ -142,7 +144,7 @@ bool SyntaxChecker::visit(ModifierDefinition const&) void SyntaxChecker::endVisit(ModifierDefinition const& _modifier) { if (_modifier.isImplemented() && !m_placeholderFound) - m_errorReporter.syntaxError(_modifier.body().location(), "Modifier body does not contain '_'."); + m_errorReporter.syntaxError(2883_error, _modifier.body().location(), "Modifier body does not contain '_'."); m_placeholderFound = false; } @@ -150,7 +152,7 @@ void SyntaxChecker::checkSingleStatementVariableDeclaration(ASTNode const& _stat { auto varDecl = dynamic_cast(&_statement); if (varDecl) - m_errorReporter.syntaxError(_statement.location(), "Variable declarations can only be used inside blocks."); + m_errorReporter.syntaxError(9079_error, _statement.location(), "Variable declarations can only be used inside blocks."); } bool SyntaxChecker::visit(IfStatement const& _ifStatement) @@ -189,7 +191,7 @@ bool SyntaxChecker::visit(Continue const& _continueStatement) { if (m_inLoopDepth <= 0) // we're not in a for/while loop, report syntax error - m_errorReporter.syntaxError(_continueStatement.location(), "\"continue\" has to be in a \"for\" or \"while\" loop."); + m_errorReporter.syntaxError(4123_error, _continueStatement.location(), "\"continue\" has to be in a \"for\" or \"while\" loop."); return true; } @@ -197,13 +199,14 @@ bool SyntaxChecker::visit(Break const& _breakStatement) { if (m_inLoopDepth <= 0) // we're not in a for/while loop, report syntax error - m_errorReporter.syntaxError(_breakStatement.location(), "\"break\" has to be in a \"for\" or \"while\" loop."); + m_errorReporter.syntaxError(6102_error, _breakStatement.location(), "\"break\" has to be in a \"for\" or \"while\" loop."); return true; } bool SyntaxChecker::visit(Throw const& _throwStatement) { m_errorReporter.syntaxError( + 4538_error, _throwStatement.location(), "\"throw\" is deprecated in favour of \"revert()\", \"require()\" and \"assert()\"." ); @@ -222,29 +225,29 @@ bool SyntaxChecker::visit(Literal const& _literal) // Generic checks no matter what base this number literal is of: if (value.back() == '_') { - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No trailing underscores allowed."); + m_errorReporter.syntaxError(2090_error, _literal.location(), "Invalid use of underscores in number literal. No trailing underscores allowed."); return true; } if (value.find("__") != ASTString::npos) { - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. Only one consecutive underscores between digits allowed."); + m_errorReporter.syntaxError(2990_error, _literal.location(), "Invalid use of underscores in number literal. Only one consecutive underscores between digits allowed."); return true; } if (!_literal.isHexNumber()) // decimal literal { if (value.find("._") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); + m_errorReporter.syntaxError(3891_error, _literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); if (value.find("_.") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); + m_errorReporter.syntaxError(1023_error, _literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); if (value.find("_e") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed."); + m_errorReporter.syntaxError(6415_error, _literal.location(), "Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed."); if (value.find("e_") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscore in front of exponent allowed."); + m_errorReporter.syntaxError(6165_error, _literal.location(), "Invalid use of underscores in number literal. No underscore in front of exponent allowed."); } return true; @@ -253,7 +256,7 @@ bool SyntaxChecker::visit(Literal const& _literal) bool SyntaxChecker::visit(UnaryOperation const& _operation) { if (_operation.getOperator() == Token::Add) - m_errorReporter.syntaxError(_operation.location(), "Use of unary + is disallowed."); + m_errorReporter.syntaxError(9636_error, _operation.location(), "Use of unary + is disallowed."); return true; } @@ -265,6 +268,7 @@ bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly) if (yul::MSizeFinder::containsMSize(_inlineAssembly.dialect(), _inlineAssembly.operations())) m_errorReporter.syntaxError( + 6553_error, _inlineAssembly.location(), "The msize instruction cannot be used when the Yul optimizer is activated because " "it can change its semantics. Either disable the Yul optimizer or do not use the instruction." @@ -285,7 +289,9 @@ bool SyntaxChecker::visit(ContractDefinition const& _contract) ASTString const& contractName = _contract.name(); for (FunctionDefinition const* function: _contract.definedFunctions()) if (function->name() == contractName) - m_errorReporter.syntaxError(function->location(), + m_errorReporter.syntaxError( + 5796_error, + function->location(), "Functions are not allowed to have the same name as the contract. " "If you intend this to be a constructor, use \"constructor(...) { ... }\" to define it." ); @@ -298,15 +304,16 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function) { string suggestedVisibility = _function.isFallback() || _function.isReceive() || m_isInterface ? "external" : "public"; m_errorReporter.syntaxError( + 4937_error, _function.location(), "No visibility specified. Did you intend to add \"" + suggestedVisibility + "\"?" ); } if (m_isInterface && !_function.modifiers().empty()) - m_errorReporter.syntaxError(_function.location(), "Functions in interfaces cannot have modifiers."); + m_errorReporter.syntaxError(5842_error, _function.location(), "Functions in interfaces cannot have modifiers."); else if (!_function.isImplemented() && !_function.modifiers().empty()) - m_errorReporter.syntaxError(_function.location(), "Functions without implementation cannot have modifiers."); + m_errorReporter.syntaxError(2668_error, _function.location(), "Functions without implementation cannot have modifiers."); return true; } @@ -315,11 +322,11 @@ bool SyntaxChecker::visit(FunctionTypeName const& _node) { for (auto const& decl: _node.parameterTypeList()->parameters()) if (!decl->name().empty()) - m_errorReporter.warning(decl->location(), "Naming function type parameters is deprecated."); + m_errorReporter.warning(6162_error, decl->location(), "Naming function type parameters is deprecated."); for (auto const& decl: _node.returnParameterTypeList()->parameters()) if (!decl->name().empty()) - m_errorReporter.syntaxError(decl->location(), "Return parameters in function types may not be named."); + m_errorReporter.syntaxError(7304_error, decl->location(), "Return parameters in function types may not be named."); return true; } @@ -327,8 +334,13 @@ bool SyntaxChecker::visit(FunctionTypeName const& _node) bool SyntaxChecker::visit(VariableDeclarationStatement const& _statement) { // Report if none of the variable components in the tuple have a name (only possible via deprecated "var") - if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr)) + if (std::all_of( + _statement.declarations().begin(), + _statement.declarations().end(), + [](ASTPointer const& declaration) { return declaration == nullptr; } + )) m_errorReporter.syntaxError( + 3299_error, _statement.location(), "The use of the \"var\" keyword is disallowed. The declaration part of the statement can be removed, since it is empty." ); @@ -339,7 +351,7 @@ bool SyntaxChecker::visit(VariableDeclarationStatement const& _statement) bool SyntaxChecker::visit(StructDefinition const& _struct) { if (_struct.members().empty()) - m_errorReporter.syntaxError(_struct.location(), "Defining empty structs is disallowed."); + m_errorReporter.syntaxError(5306_error, _struct.location(), "Defining empty structs is disallowed."); return true; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b4030c0c4e18..ebb7bf6e6874 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -34,7 +34,6 @@ #include #include -#include #include #include @@ -117,6 +116,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment) } if (storageToStorageCopies >= 1 && toStorageCopies >= 2) m_errorReporter.warning( + 7238_error, _assignment.location(), "This assignment performs two copies to storage. Since storage copies do not first " "copy to a temporary location, one of them might be overwritten before the second " @@ -130,6 +130,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c vector> arguments = _functionCall.arguments(); if (arguments.size() != 2) m_errorReporter.typeError( + 5782_error, _functionCall.location(), "This function takes two arguments, but " + toString(arguments.size()) + @@ -142,6 +143,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c !type(*arguments.front())->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()) ) m_errorReporter.typeError( + 1956_error, arguments.front()->location(), "The first argument to \"abi.decode\" must be implicitly convertible to " "bytes memory or bytes calldata, but is of type " + @@ -158,6 +160,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c if (!tupleExpression) { m_errorReporter.typeError( + 6444_error, arguments[1]->location(), "The second argument to \"abi.decode\" has to be a tuple of types." ); @@ -186,6 +189,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c ); if (!actualType->fullEncodingType(false, _abiEncoderV2, false)) m_errorReporter.typeError( + 9611_error, typeArgument->location(), "Decoding type " + actualType->toString(false) + " not supported." ); @@ -193,7 +197,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c } else { - m_errorReporter.typeError(typeArgument->location(), "Argument has to be a type name."); + m_errorReporter.typeError(1039_error, typeArgument->location(), "Argument has to be a type name."); components.push_back(TypeProvider::emptyTuple()); } } @@ -206,6 +210,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio if (arguments.size() != 1) { m_errorReporter.typeError( + 8885_error, _functionCall.location(), "This function takes one argument, but " + toString(arguments.size()) + @@ -214,17 +219,29 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio return {}; } TypePointer firstArgType = type(*arguments.front()); - if ( - firstArgType->category() != Type::Category::TypeType || - dynamic_cast(*firstArgType).actualType()->category() != TypeType::Category::Contract - ) + + bool wrongType = false; + if (firstArgType->category() == Type::Category::TypeType) + { + TypeType const* typeTypePtr = dynamic_cast(firstArgType); + Type::Category typeCategory = typeTypePtr->actualType()->category(); + if ( + typeCategory != Type::Category::Contract && + typeCategory != Type::Category::Integer + ) + wrongType = true; + } + else + wrongType = true; + + if (wrongType) { m_errorReporter.typeError( + 4259_error, arguments.front()->location(), - "Invalid type for argument in function call. " - "Contract type required, but " + - type(*arguments.front())->toString(true) + - " provided." + "Invalid type for argument in the function call. " + "A contract type or an integer type is required, but " + + type(*arguments.front())->toString(true) + " provided." ); return {}; } @@ -238,10 +255,10 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) solAssert(base, "Base contract not available."); if (m_scope->isInterface() && !base->isInterface()) - m_errorReporter.typeError(_inheritance.location(), "Interfaces can only inherit from other interfaces."); + m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces."); if (base->isLibrary()) - m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from."); + m_errorReporter.typeError(2571_error, _inheritance.location(), "Libraries cannot be inherited from."); auto const& arguments = _inheritance.arguments(); TypePointers parameterTypes; @@ -254,6 +271,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) if (parameterTypes.size() != arguments->size()) { m_errorReporter.typeError( + 7927_error, _inheritance.location(), "Wrong argument count for constructor call: " + toString(arguments->size()) + @@ -267,6 +285,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) BoolResult result = type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 9827_error, (*arguments)[i]->location(), "Invalid type for argument in constructor call. " "Invalid implicit conversion from " + @@ -286,13 +305,13 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) _usingFor.libraryName().annotation().referencedDeclaration ); if (!library || !library->isLibrary()) - m_errorReporter.fatalTypeError(_usingFor.libraryName().location(), "Library name expected."); + m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected."); } void TypeChecker::endVisit(ModifierDefinition const& _modifier) { if (!_modifier.isImplemented() && !_modifier.virtualSemantics()) - m_errorReporter.typeError(_modifier.location(), "Modifiers without implementation must be marked virtual."); + m_errorReporter.typeError(8063_error, _modifier.location(), "Modifiers without implementation must be marked virtual."); } bool TypeChecker::visit(FunctionDefinition const& _function) @@ -302,17 +321,17 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (_function.markedVirtual()) { if (_function.annotation().contract->isInterface()) - m_errorReporter.warning(_function.location(), "Interface functions are implicitly \"virtual\""); + m_errorReporter.warning(5815_error, _function.location(), "Interface functions are implicitly \"virtual\""); if (_function.visibility() == Visibility::Private) - m_errorReporter.typeError(_function.location(), "\"virtual\" and \"private\" cannot be used together."); + m_errorReporter.typeError(3942_error, _function.location(), "\"virtual\" and \"private\" cannot be used together."); } if (_function.isPayable()) { if (isLibraryFunction) - m_errorReporter.typeError(_function.location(), "Library functions cannot be payable."); + m_errorReporter.typeError(7708_error, _function.location(), "Library functions cannot be payable."); if (_function.isOrdinary() && !_function.isPartOfExternalInterface()) - m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable."); + m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable."); } auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& var) { if (type(var)->category() == Type::Category::Mapping) @@ -320,9 +339,9 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (var.referenceLocation() != VariableDeclaration::Location::Storage) { if (!isLibraryFunction && _function.isPublic()) - m_errorReporter.typeError(var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions."); + m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions."); else - m_errorReporter.typeError(var.location(), "Mapping types can only have a data location of \"storage\"." ); + m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." ); } else { @@ -332,7 +351,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) else { if (!type(var)->canLiveOutsideStorage() && _function.isPublic()) - m_errorReporter.typeError(var.location(), "Type is required to live outside storage."); + m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage."); if (_function.isPublic()) { auto iType = type(var)->interfaceType(isLibraryFunction); @@ -340,7 +359,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (!iType) { solAssert(!iType.message().empty(), "Expected detailed error message!"); - m_errorReporter.fatalTypeError(var.location(), iType.message()); + m_errorReporter.fatalTypeError(4103_error, var.location(), iType.message()); } } } @@ -350,6 +369,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) !typeSupportedByOldABIEncoder(*type(var), isLibraryFunction) ) m_errorReporter.typeError( + 4957_error, var.location(), "This type is only supported in ABIEncoderV2. " "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." @@ -380,7 +400,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (modifiers.count(decl)) { if (dynamic_cast(decl)) - m_errorReporter.declarationError(modifier->location(), "Base constructor already provided."); + m_errorReporter.declarationError(1697_error, modifier->location(), "Base constructor already provided."); } else modifiers.insert(decl); @@ -388,25 +408,25 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (m_scope->isInterface()) { if (_function.isImplemented()) - m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot have an implementation."); + m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation."); if (_function.visibility() != Visibility::External) - m_errorReporter.typeError(_function.location(), "Functions in interfaces must be declared external."); + m_errorReporter.typeError(1560_error, _function.location(), "Functions in interfaces must be declared external."); if (_function.isConstructor()) - m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces."); + m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces."); } else if (m_scope->contractKind() == ContractKind::Library) if (_function.isConstructor()) - m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in libraries."); + m_errorReporter.typeError(7634_error, _function.location(), "Constructor cannot be defined in libraries."); if (_function.isImplemented()) _function.body().accept(*this); else if (_function.isConstructor()) - m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared."); + m_errorReporter.typeError(5700_error, _function.location(), "Constructor must be implemented if declared."); else if (isLibraryFunction) - m_errorReporter.typeError(_function.location(), "Library functions must be implemented if declared."); + m_errorReporter.typeError(9231_error, _function.location(), "Library functions must be implemented if declared."); else if (!_function.virtualSemantics()) - m_errorReporter.typeError(_function.location(), "Functions without implementation must be marked virtual."); + m_errorReporter.typeError(5424_error, _function.location(), "Functions without implementation must be marked virtual."); if (_function.isFallback()) @@ -431,7 +451,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (auto contractType = dynamic_cast(varType)) if (contractType->contractDefinition().isLibrary()) - m_errorReporter.typeError(_variable.location(), "The type of a variable cannot be a library."); + m_errorReporter.typeError(1273_error, _variable.location(), "The type of a variable cannot be a library."); if (_variable.value()) expectType(*_variable.value(), *varType); if (_variable.isConstant()) @@ -442,13 +462,14 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (auto arrayType = dynamic_cast(_variable.type())) allowed = arrayType->isByteArray(); if (!allowed) - m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented."); + m_errorReporter.typeError(9259_error, _variable.location(), "Constants of non-value type not yet implemented."); } if (!_variable.value()) - m_errorReporter.typeError(_variable.location(), "Uninitialized \"constant\" variable."); + m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable."); else if (!_variable.value()->annotation().isPure) m_errorReporter.typeError( + 8349_error, _variable.value()->location(), "Initial value for constant variable has to be compile-time constant." ); @@ -456,12 +477,12 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) else if (_variable.immutable()) { if (!_variable.type()->isValueType()) - m_errorReporter.typeError(_variable.location(), "Immutable variables cannot have a non-value type."); + m_errorReporter.typeError(6377_error, _variable.location(), "Immutable variables cannot have a non-value type."); if ( auto const* functionType = dynamic_cast(_variable.type()); functionType && functionType->kind() == FunctionType::Kind::External ) - m_errorReporter.typeError(_variable.location(), "Immutable variables of external function type are not yet supported."); + m_errorReporter.typeError(3366_error, _variable.location(), "Immutable variables of external function type are not yet supported."); solAssert(_variable.type()->sizeOnStack() == 1 || m_errorReporter.hasErrors(), ""); } @@ -469,7 +490,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) { if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData)) if (!varType->canLiveOutsideStorage()) - m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage."); + m_errorReporter.typeError(4061_error, _variable.location(), "Type " + varType->toString() + " is only valid in storage."); } else if (_variable.visibility() >= Visibility::Public) { @@ -481,14 +502,16 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (!typeSupportedByOldABIEncoder(*param, false /* isLibrary */)) unsupportedTypes.emplace_back(param->toString()); if (!unsupportedTypes.empty()) - m_errorReporter.typeError(_variable.location(), + m_errorReporter.typeError( + 2763_error, + _variable.location(), "The following types are only supported for getters in ABIEncoderV2: " + joinHumanReadable(unsupportedTypes) + ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature." ); } if (!getter.interfaceFunctionType()) - m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables."); + m_errorReporter.typeError(6744_error, _variable.location(), "Internal or recursive type is not allowed for public state variables."); } if (auto referenceType = dynamic_cast(varType)) @@ -499,7 +522,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (!result) { solAssert(!result.message().empty(), "Expected detailed error message"); - m_errorReporter.typeError(_variable.location(), result.message()); + m_errorReporter.typeError(1534_error, _variable.location(), result.message()); } } @@ -536,12 +559,13 @@ void TypeChecker::visitManually( } if (!parameters) { - m_errorReporter.typeError(_modifier.location(), "Referenced declaration is neither modifier nor base class."); + m_errorReporter.typeError(4659_error, _modifier.location(), "Referenced declaration is neither modifier nor base class."); return; } if (parameters->size() != arguments.size()) { m_errorReporter.typeError( + 2973_error, _modifier.location(), "Wrong argument count for modifier invocation: " + toString(arguments.size()) + @@ -556,6 +580,7 @@ void TypeChecker::visitManually( BoolResult result = type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 4649_error, arguments[i]->location(), "Invalid type for argument in modifier invocation. " "Invalid implicit conversion from " + @@ -577,23 +602,24 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) if (var->isIndexed()) numIndexed++; if (!type(*var)->canLiveOutsideStorage()) - m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); + m_errorReporter.typeError(3448_error, var->location(), "Type is required to live outside storage."); if (!type(*var)->interfaceType(false)) - m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type."); + m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type."); if ( !_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && !typeSupportedByOldABIEncoder(*type(*var), false /* isLibrary */) ) m_errorReporter.typeError( + 3061_error, var->location(), "This type is only supported in ABIEncoderV2. " "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." ); } if (_eventDef.isAnonymous() && numIndexed > 4) - m_errorReporter.typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event."); + m_errorReporter.typeError(8598_error, _eventDef.location(), "More than 4 indexed arguments for anonymous event."); else if (!_eventDef.isAnonymous() && numIndexed > 3) - m_errorReporter.typeError(_eventDef.location(), "More than 3 indexed arguments for event."); + m_errorReporter.typeError(7249_error, _eventDef.location(), "More than 3 indexed arguments for event."); return false; } @@ -606,7 +632,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType) { solAssert(t->annotation().type, "Type not set for parameter."); if (!t->annotation().type->interfaceType(false).get()) - m_errorReporter.typeError(t->location(), "Internal type cannot be used for external function type."); + m_errorReporter.typeError(2582_error, t->location(), "Internal type cannot be used for external function type."); } solAssert(fun.interfaceType(false), "External function type uses internal types."); } @@ -633,7 +659,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(var->type(), "Expected variable type!"); if (var->immutable()) { - m_errorReporter.typeError(_identifier.location, "Assembly access to immutable variables is not supported."); + m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported."); return size_t(-1); } if (var->isConstant()) @@ -642,7 +668,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var && !var->value()) { - m_errorReporter.typeError(_identifier.location, "Constant has no value."); + m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value."); return size_t(-1); } else if (!var || !type(*var)->isValueType() || ( @@ -650,17 +676,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) type(*var->value())->category() != Type::Category::RationalNumber )) { - m_errorReporter.typeError(_identifier.location, "Only direct number constants and references to such constants are supported by inline assembly."); + m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly."); return size_t(-1); } else if (_context == yul::IdentifierContext::LValue) { - m_errorReporter.typeError(_identifier.location, "Constant variables cannot be assigned to."); + m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to."); return size_t(-1); } else if (requiresStorage) { - m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); + m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); return size_t(-1); } } @@ -669,19 +695,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { - m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); + m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); return size_t(-1); } else if (_context == yul::IdentifierContext::LValue) { if (var->isStateVariable()) { - m_errorReporter.typeError(_identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); + m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); return size_t(-1); } else if (ref->second.isOffset) { - m_errorReporter.typeError(_identifier.location, "Only _slot can be assigned to."); + m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to."); return size_t(-1); } else @@ -690,26 +716,26 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) } else if (!var->isConstant() && var->isStateVariable()) { - m_errorReporter.typeError(_identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); + m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); return size_t(-1); } else if (var->type()->dataStoredIn(DataLocation::Storage)) { - m_errorReporter.typeError(_identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); + m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); return size_t(-1); } else if (var->type()->sizeOnStack() != 1) { if (var->type()->dataStoredIn(DataLocation::CallData)) - m_errorReporter.typeError(_identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); + m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); else - m_errorReporter.typeError(_identifier.location, "Only types that use one stack slot are supported."); + m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported."); return size_t(-1); } } else if (requiresStorage) { - m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); + m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); return size_t(-1); } else if (_context == yul::IdentifierContext::LValue) @@ -717,7 +743,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (dynamic_cast(declaration)) return size_t(-1); - m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly."); + m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly."); return size_t(-1); } @@ -726,7 +752,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(!!declaration->type(), "Type of declaration required but not yet determined."); if (dynamic_cast(declaration)) { - m_errorReporter.declarationError(_identifier.location, "Access to functions is not allowed in inline assembly."); + m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly."); return size_t(-1); } else if (dynamic_cast(declaration)) @@ -736,7 +762,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (!contract->isLibrary()) { - m_errorReporter.typeError(_identifier.location, "Expected a library."); + m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library."); return size_t(-1); } } @@ -774,6 +800,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) if (!externalCall || externalCall->annotation().kind != FunctionCallKind::FunctionCall) { m_errorReporter.typeError( + 5347_error, _tryStatement.externalCall().location(), "Try can only be used with external function calls and contract creation calls." ); @@ -788,6 +815,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) ) { m_errorReporter.typeError( + 2536_error, _tryStatement.externalCall().location(), "Try can only be used with external function calls and contract creation calls." ); @@ -810,6 +838,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) successClause.parameters()->parameters(); if (returnTypes.size() != parameters.size()) m_errorReporter.typeError( + 2800_error, successClause.location(), "Function returns " + to_string(functionType.returnParameterTypes().size()) + @@ -823,6 +852,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) solAssert(returnTypes[i], ""); if (parameters[i] && *parameters[i]->annotation().type != *returnTypes[i]) m_errorReporter.typeError( + 6509_error, parameters[i]->location(), "Invalid type, expected " + returnTypes[i]->toString(false) + @@ -842,6 +872,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) { if (lowLevelClause) m_errorReporter.typeError( + 5320_error, clause.location(), SecondarySourceLocation{}.append("The first clause is here:", lowLevelClause->location()), "This try statement already has a low-level catch clause." @@ -853,9 +884,10 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) clause.parameters()->parameters().size() != 1 || *clause.parameters()->parameters().front()->type() != *TypeProvider::bytesMemory() ) - m_errorReporter.typeError(clause.location(), "Expected `catch (bytes memory ...) { ... }` or `catch { ... }`."); + m_errorReporter.typeError(6231_error, clause.location(), "Expected `catch (bytes memory ...) { ... }` or `catch { ... }`."); if (!m_evmVersion.supportsReturndata()) m_errorReporter.typeError( + 9908_error, clause.location(), "This catch clause type cannot be used on the selected EVM version (" + m_evmVersion.name() + @@ -867,6 +899,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) { if (!m_evmVersion.supportsReturndata()) m_errorReporter.typeError( + 1812_error, clause.location(), "This catch clause type cannot be used on the selected EVM version (" + m_evmVersion.name() + @@ -875,6 +908,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) if (errorClause) m_errorReporter.typeError( + 1036_error, clause.location(), SecondarySourceLocation{}.append("The first clause is here:", errorClause->location()), "This try statement already has an \"Error\" catch clause." @@ -885,10 +919,11 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) clause.parameters()->parameters().size() != 1 || *clause.parameters()->parameters().front()->type() != *TypeProvider::stringMemory() ) - m_errorReporter.typeError(clause.location(), "Expected `catch Error(string memory ...) { ... }`."); + m_errorReporter.typeError(2943_error, clause.location(), "Expected `catch Error(string memory ...) { ... }`."); } else m_errorReporter.typeError( + 3542_error, clause.location(), "Invalid catch clause name. Expected either `catch (...)` or `catch Error(...)`." ); @@ -920,12 +955,12 @@ void TypeChecker::endVisit(Return const& _return) if (!_return.expression()) { if (params && !params->parameters().empty()) - m_errorReporter.typeError(_return.location(), "Return arguments required."); + m_errorReporter.typeError(6777_error, _return.location(), "Return arguments required."); return; } if (!params) { - m_errorReporter.typeError(_return.location(), "Return arguments not allowed."); + m_errorReporter.typeError(7552_error, _return.location(), "Return arguments not allowed."); return; } TypePointers returnTypes; @@ -934,12 +969,13 @@ void TypeChecker::endVisit(Return const& _return) if (auto tupleType = dynamic_cast(type(*_return.expression()))) { if (tupleType->components().size() != params->parameters().size()) - m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration."); + m_errorReporter.typeError(5132_error, _return.location(), "Different number of arguments in return statement than in returns declaration."); else { BoolResult result = tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes)); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 5992_error, _return.expression()->location(), "Return argument type " + type(*_return.expression())->toString() + @@ -950,13 +986,14 @@ void TypeChecker::endVisit(Return const& _return) } } else if (params->parameters().size() != 1) - m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration."); + m_errorReporter.typeError(8863_error, _return.location(), "Different number of arguments in return statement than in returns declaration."); else { TypePointer const& expected = type(*params->parameters().front()); BoolResult result = type(*_return.expression())->isImplicitlyConvertibleTo(*expected); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 6359_error, _return.expression()->location(), "Return argument type " + type(*_return.expression())->toString() + @@ -974,7 +1011,7 @@ void TypeChecker::endVisit(EmitStatement const& _emit) type(_emit.eventCall().expression())->category() != Type::Category::Function || dynamic_cast(*type(_emit.eventCall().expression())).kind() != FunctionType::Kind::Event ) - m_errorReporter.typeError(_emit.eventCall().expression().location(), "Expression has to be an event invocation."); + m_errorReporter.typeError(9292_error, _emit.eventCall().expression().location(), "Expression has to be an event invocation."); } namespace @@ -1031,7 +1068,11 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) // No initial value is only permitted for single variables with specified type. if (_statement.declarations().size() != 1 || !_statement.declarations().front()) { - if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr)) + if (std::all_of( + _statement.declarations().begin(), + _statement.declarations().end(), + [](ASTPointer const& declaration) { return declaration == nullptr; } + )) { // The syntax checker has already generated an error for this case (empty LHS tuple). solAssert(m_errorReporter.hasErrors(), ""); @@ -1042,15 +1083,16 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) } else // Bailing out *fatal* here, as those (untyped) vars may be used later, and diagnostics wouldn't be helpful then. - m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed."); + m_errorReporter.fatalTypeError(4626_error, _statement.location(), "Use of the \"var\" keyword is disallowed."); } VariableDeclaration const& varDecl = *_statement.declarations().front(); if (!varDecl.annotation().type) - m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed."); + m_errorReporter.fatalTypeError(6983_error, _statement.location(), "Use of the \"var\" keyword is disallowed."); if (dynamic_cast(type(varDecl))) m_errorReporter.typeError( + 4182_error, varDecl.location(), "Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable." ); @@ -1074,6 +1116,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) solAssert(m_errorReporter.hasErrors(), ""); else if (valueTypes.size() != variables.size()) m_errorReporter.typeError( + 7364_error, _statement.location(), "Different number of components on the left hand side (" + toString(variables.size()) + @@ -1103,6 +1146,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { if (valueComponentType->category() == Type::Category::RationalNumber) m_errorReporter.fatalTypeError( + 6963_error, _statement.initialValue()->location(), "Invalid rational " + valueComponentType->toString() + @@ -1158,11 +1202,13 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { if (var.annotation().type->operator==(*valueComponentType->mobileType())) m_errorReporter.typeError( + 5107_error, _statement.location(), errorMsg + ", but it can be explicitly converted." ); else m_errorReporter.typeError( + 4486_error, _statement.location(), errorMsg + ". Try converting to type " + @@ -1172,6 +1218,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) } else m_errorReporter.typeErrorConcatenateDescriptions( + 9574_error, _statement.location(), errorMsg + ".", result.message() @@ -1192,12 +1239,14 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { if (!typeCanBeExpressed(variables)) m_errorReporter.syntaxError( + 3478_error, _statement.location(), "Use of the \"var\" keyword is disallowed. " "Type cannot be expressed in syntax." ); else m_errorReporter.syntaxError( + 1719_error, _statement.location(), "Use of the \"var\" keyword is disallowed. " "Use explicit declaration `" + createTupleDecl(variables) + " = ...´ instead." @@ -1211,7 +1260,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) { if (type(_statement.expression())->category() == Type::Category::RationalNumber) if (!dynamic_cast(*type(_statement.expression())).mobileType()) - m_errorReporter.typeError(_statement.expression().location(), "Invalid rational number."); + m_errorReporter.typeError(3757_error, _statement.expression().location(), "Invalid rational number."); if (auto call = dynamic_cast(&_statement.expression())) { @@ -1224,9 +1273,9 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) kind == FunctionType::Kind::BareDelegateCall || kind == FunctionType::Kind::BareStaticCall ) - m_errorReporter.warning(_statement.location(), "Return value of low-level calls not used."); + m_errorReporter.warning(9302_error, _statement.location(), "Return value of low-level calls not used."); else if (kind == FunctionType::Kind::Send) - m_errorReporter.warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead."); + m_errorReporter.warning(5878_error, _statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead."); } } } @@ -1244,12 +1293,12 @@ bool TypeChecker::visit(Conditional const& _conditional) TypePointer commonType = nullptr; if (!trueType) - m_errorReporter.typeError(_conditional.trueExpression().location(), "Invalid mobile type in true expression."); + m_errorReporter.typeError(9717_error, _conditional.trueExpression().location(), "Invalid mobile type in true expression."); else commonType = trueType; if (!falseType) - m_errorReporter.typeError(_conditional.falseExpression().location(), "Invalid mobile type in false expression."); + m_errorReporter.typeError(3703_error, _conditional.falseExpression().location(), "Invalid mobile type in false expression."); else commonType = falseType; @@ -1262,6 +1311,7 @@ bool TypeChecker::visit(Conditional const& _conditional) if (!commonType) { m_errorReporter.typeError( + 1080_error, _conditional.location(), "True expression's type " + trueType->toString() + @@ -1283,6 +1333,7 @@ bool TypeChecker::visit(Conditional const& _conditional) if (_conditional.annotation().willBeWrittenTo) m_errorReporter.typeError( + 2212_error, _conditional.location(), "Conditional expression as left value is not supported yet." ); @@ -1295,7 +1346,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& if (auto const* tupleExpression = dynamic_cast(&_expression)) { if (tupleExpression->components().empty()) - m_errorReporter.typeError(_expression.location(), "Empty tuple on the left hand side."); + m_errorReporter.typeError(5547_error, _expression.location(), "Empty tuple on the left hand side."); auto const* tupleType = dynamic_cast(&_type); auto const& types = tupleType && tupleExpression->components().size() != 1 ? tupleType->components() : vector { &_type }; @@ -1320,7 +1371,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& if (variableDeclaration->isLocalOrReturn()) isLocalOrReturn = true; if (!isLocalOrReturn) - m_errorReporter.typeError(_expression.location(), "Mappings cannot be assigned to."); + m_errorReporter.typeError(9214_error, _expression.location(), "Mappings cannot be assigned to."); } } @@ -1339,6 +1390,7 @@ bool TypeChecker::visit(Assignment const& _assignment) { if (_assignment.assignmentOperator() != Token::Assign) m_errorReporter.typeError( + 4289_error, _assignment.location(), "Compound assignment is not allowed for tuple types." ); @@ -1363,6 +1415,7 @@ bool TypeChecker::visit(Assignment const& _assignment) ); if (!resultType || *resultType != *t) m_errorReporter.typeError( + 7366_error, _assignment.location(), "Operator " + string(TokenTraits::toString(_assignment.assignmentOperator())) + @@ -1383,7 +1436,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) if (_tuple.annotation().willBeWrittenTo) { if (_tuple.isInlineArray()) - m_errorReporter.fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue."); + m_errorReporter.fatalTypeError(3025_error, _tuple.location(), "Inline array type cannot be declared as LValue."); for (auto const& component: components) if (component) { @@ -1410,7 +1463,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) for (size_t i = 0; i < components.size(); ++i) { if (!components[i]) - m_errorReporter.fatalTypeError(_tuple.location(), "Tuple component cannot be empty."); + m_errorReporter.fatalTypeError(8381_error, _tuple.location(), "Tuple component cannot be empty."); components[i]->accept(*this); types.push_back(type(*components[i])); @@ -1419,21 +1472,21 @@ bool TypeChecker::visit(TupleExpression const& _tuple) if (dynamic_cast(*types[i]).components().empty()) { if (_tuple.isInlineArray()) - m_errorReporter.fatalTypeError(components[i]->location(), "Array component cannot be empty."); - m_errorReporter.typeError(components[i]->location(), "Tuple component cannot be empty."); + m_errorReporter.fatalTypeError(5604_error, components[i]->location(), "Array component cannot be empty."); + m_errorReporter.typeError(6473_error, components[i]->location(), "Tuple component cannot be empty."); } // Note: code generation will visit each of the expression even if they are not assigned from. if (types[i]->category() == Type::Category::RationalNumber && components.size() > 1) if (!dynamic_cast(*types[i]).mobileType()) - m_errorReporter.fatalTypeError(components[i]->location(), "Invalid rational number."); + m_errorReporter.fatalTypeError(3390_error, components[i]->location(), "Invalid rational number."); if (_tuple.isInlineArray()) { solAssert(!!types[i], "Inline array cannot have empty components"); if ((i == 0 || inlineArrayType) && !types[i]->mobileType()) - m_errorReporter.fatalTypeError(components[i]->location(), "Invalid mobile type."); + m_errorReporter.fatalTypeError(9563_error, components[i]->location(), "Invalid mobile type."); if (i == 0) inlineArrayType = types[i]->mobileType(); @@ -1447,9 +1500,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) { if (!inlineArrayType) - m_errorReporter.fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements."); + m_errorReporter.fatalTypeError(6378_error, _tuple.location(), "Unable to deduce common type for array elements."); else if (!inlineArrayType->canLiveOutsideStorage()) - m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage."); + m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage."); _tuple.annotation().type = TypeProvider::array(DataLocation::Memory, inlineArrayType, types.size()); } @@ -1482,9 +1535,9 @@ bool TypeChecker::visit(UnaryOperation const& _operation) if (modifying) // Cannot just report the error, ignore the unary operator, and continue, // because the sub-expression was already processed with requireLValue() - m_errorReporter.fatalTypeError(_operation.location(), description); + m_errorReporter.fatalTypeError(9767_error, _operation.location(), description); else - m_errorReporter.typeError(_operation.location(), description); + m_errorReporter.typeError(4907_error, _operation.location(), description); t = subExprType; } _operation.annotation().type = t; @@ -1501,6 +1554,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) if (!commonType) { m_errorReporter.typeError( + 2271_error, _operation.location(), "Operator " + string(TokenTraits::toString(_operation.getOperator())) + @@ -1536,6 +1590,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) dynamic_cast(*commonType).numBits() != 256 )) m_errorReporter.warning( + 9085_error, _operation.location(), "Result of " + operation + " has type " + commonType->toString() + " and thus " "might overflow. Silence this warning by converting the literal to the " @@ -1548,6 +1603,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) dynamic_cast(*rightType).numBits() ) m_errorReporter.warning( + 3149_error, _operation.location(), "The result type of the " + operation + @@ -1574,11 +1630,13 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( TypePointer resultType = dynamic_cast(*expressionType).actualType(); if (arguments.size() != 1) m_errorReporter.typeError( + 2558_error, _functionCall.location(), "Exactly one argument expected for explicit type conversion." ); else if (!isPositionalCall) m_errorReporter.typeError( + 5153_error, _functionCall.location(), "Type conversion cannot allow named arguments." ); @@ -1639,6 +1697,7 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( variableDeclaration->location() ); m_errorReporter.typeError( + 7398_error, _functionCall.location(), ssl, "Explicit type conversion not allowed from non-payable \"address\" to \"" + @@ -1653,6 +1712,7 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( resultType->category() == Type::Category::Address ) m_errorReporter.typeError( + 5030_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + argType->toString() + @@ -1663,6 +1723,7 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( ); else m_errorReporter.typeError( + 9640_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + argType->toString() + @@ -1700,11 +1761,13 @@ void TypeChecker::typeCheckFunctionCall( !dynamic_cast(_functionType->declaration()).isImplemented() ) m_errorReporter.typeError( + 7501_error, _functionCall.location(), "Cannot call unimplemented base function." ); else m_errorReporter.typeError( + 3419_error, _functionCall.location(), "Cannot call function via contract type name." ); @@ -1717,6 +1780,7 @@ void TypeChecker::typeCheckFunctionCall( !m_evmVersion.hasStaticCall() ) m_errorReporter.typeError( + 5052_error, _functionCall.location(), "\"staticcall\" is not supported by the VM version." ); @@ -1730,25 +1794,26 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function) solAssert(_function.isFallback(), ""); if (_function.inContractKind() == ContractKind::Library) - m_errorReporter.typeError(_function.location(), "Libraries cannot have fallback functions."); + m_errorReporter.typeError(5982_error, _function.location(), "Libraries cannot have fallback functions."); if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( + 4575_error, _function.location(), "Fallback function must be payable or non-payable, but is \"" + stateMutabilityToString(_function.stateMutability()) + "\"." ); if (_function.visibility() != Visibility::External) - m_errorReporter.typeError(_function.location(), "Fallback function must be defined as \"external\"."); + m_errorReporter.typeError(1159_error, _function.location(), "Fallback function must be defined as \"external\"."); if (!_function.returnParameters().empty()) { if (_function.returnParameters().size() > 1 || *type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory()) - m_errorReporter.typeError(_function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value."); + m_errorReporter.typeError(5570_error, _function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value."); else - m_errorReporter.typeError(_function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented."); + m_errorReporter.typeError(6151_error, _function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented."); } if (!_function.parameters().empty()) - m_errorReporter.typeError(_function.parameterList().location(), "Fallback function cannot take parameters."); + m_errorReporter.typeError(3978_error, _function.parameterList().location(), "Fallback function cannot take parameters."); } void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function) @@ -1756,21 +1821,22 @@ void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function) solAssert(_function.isReceive(), ""); if (_function.inContractKind() == ContractKind::Library) - m_errorReporter.typeError(_function.location(), "Libraries cannot have receive ether functions."); + m_errorReporter.typeError(4549_error, _function.location(), "Libraries cannot have receive ether functions."); if (_function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( + 7793_error, _function.location(), "Receive ether function must be payable, but is \"" + stateMutabilityToString(_function.stateMutability()) + "\"." ); if (_function.visibility() != Visibility::External) - m_errorReporter.typeError(_function.location(), "Receive ether function must be defined as \"external\"."); + m_errorReporter.typeError(4095_error, _function.location(), "Receive ether function must be defined as \"external\"."); if (!_function.returnParameters().empty()) - m_errorReporter.typeError(_function.returnParameterList()->location(), "Receive ether function cannot return values."); + m_errorReporter.typeError(6899_error, _function.returnParameterList()->location(), "Receive ether function cannot return values."); if (!_function.parameters().empty()) - m_errorReporter.typeError(_function.parameterList().location(), "Receive ether function cannot take parameters."); + m_errorReporter.typeError(6857_error, _function.parameterList().location(), "Receive ether function cannot take parameters."); } @@ -1778,20 +1844,21 @@ void TypeChecker::typeCheckConstructor(FunctionDefinition const& _function) { solAssert(_function.isConstructor(), ""); if (_function.markedVirtual()) - m_errorReporter.typeError(_function.location(), "Constructors cannot be virtual."); + m_errorReporter.typeError(7001_error, _function.location(), "Constructors cannot be virtual."); if (_function.overrides()) - m_errorReporter.typeError(_function.location(), "Constructors cannot override."); + m_errorReporter.typeError(1209_error, _function.location(), "Constructors cannot override."); if (!_function.returnParameters().empty()) - m_errorReporter.typeError(_function.returnParameterList()->location(), "Non-empty \"returns\" directive for constructor."); + m_errorReporter.typeError(9712_error, _function.returnParameterList()->location(), "Non-empty \"returns\" directive for constructor."); if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( + 1558_error, _function.location(), "Constructor must be payable or non-payable, but is \"" + stateMutabilityToString(_function.stateMutability()) + "\"." ); if (_function.visibility() != Visibility::Public && _function.visibility() != Visibility::Internal) - m_errorReporter.typeError(_function.location(), "Constructor must be public or internal."); + m_errorReporter.typeError(9239_error, _function.location(), "Constructor must be public or internal."); } void TypeChecker::typeCheckABIEncodeFunctions( @@ -1820,6 +1887,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (!_functionCall.names().empty()) { m_errorReporter.typeError( + 2627_error, _functionCall.location(), "Named arguments cannot be used for functions that take arbitrary parameters." ); @@ -1841,6 +1909,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (rationalType.isFractional()) { m_errorReporter.typeError( + 6090_error, arguments[i]->location(), "Fractional numbers cannot yet be encoded." ); @@ -1849,6 +1918,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( else if (!argType->mobileType()) { m_errorReporter.typeError( + 8009_error, arguments[i]->location(), "Invalid rational number (too large or division by zero)." ); @@ -1857,6 +1927,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( else if (isPacked) { m_errorReporter.typeError( + 7279_error, arguments[i]->location(), "Cannot perform packed encoding for a literal." " Please convert it to an explicit type first." @@ -1868,6 +1939,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (isPacked && !typeSupportedByOldABIEncoder(*argType, false /* isLibrary */)) { m_errorReporter.typeError( + 9578_error, arguments[i]->location(), "Type not supported in packed mode." ); @@ -1876,6 +1948,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (!argType->fullEncodingType(false, abiEncoderV2, !_functionType->padArguments())) m_errorReporter.typeError( + 2056_error, arguments[i]->location(), "This type cannot be encoded." ); @@ -1977,7 +2050,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( " This function requires a single bytes argument." " Use abi.encodePacked(...) to obtain the pre-0.5.0" " behaviour or abi.encode(...) to use ABI encoding."; - m_errorReporter.typeError(_functionCall.location(), msg); + m_errorReporter.typeError(1093_error, _functionCall.location(), msg); return; } @@ -2006,6 +2079,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( { duplication = true; m_errorReporter.typeError( + 6995_error, arguments[i]->location(), "Duplicate named argument \"" + *argumentNames[i] + "\"." ); @@ -2032,6 +2106,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( paramArgMap[i] = nullptr; not_all_mapped = true; m_errorReporter.typeError( + 4974_error, _functionCall.location(), "Named argument \"" + *argumentNames[i] + @@ -2077,7 +2152,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( " This function requires a single bytes argument." " Use abi.encodePacked(...) to obtain the pre-0.5.0" " behaviour or abi.encode(...) to use ABI encoding."; - m_errorReporter.typeError(paramArgMap[i]->location(), msg); + m_errorReporter.typeError(6706_error, paramArgMap[i]->location(), msg); } } } @@ -2159,7 +2234,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) } default: - m_errorReporter.fatalTypeError(_functionCall.location(), "Type is not callable"); + m_errorReporter.fatalTypeError(5704_error, _functionCall.location(), "Type is not callable"); funcCallAnno.kind = FunctionCallKind::Unset; funcCallAnno.isPure = argumentsArePure; break; @@ -2238,7 +2313,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) auto expressionFunctionType = dynamic_cast(type(_functionCallOptions.expression())); if (!expressionFunctionType) { - m_errorReporter.fatalTypeError(_functionCallOptions.location(), "Expected callable expression before call options."); + m_errorReporter.fatalTypeError(2622_error, _functionCallOptions.location(), "Expected callable expression before call options."); return false; } @@ -2257,6 +2332,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) ) { m_errorReporter.fatalTypeError( + 2193_error, _functionCallOptions.location(), "Function call options can only be set on external function calls or contract creations." ); @@ -2267,6 +2343,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) { if (_option || _alreadySet) m_errorReporter.typeError( + 9886_error, _functionCallOptions.location(), _alreadySet ? "Option \"" + std::move(_name) + "\" has already been set." : @@ -2288,6 +2365,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) } else m_errorReporter.typeError( + 2721_error, _functionCallOptions.location(), "Function call option \"salt\" can only be used with \"new\"." ); @@ -2296,16 +2374,19 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) { if (kind == FunctionType::Kind::BareDelegateCall) m_errorReporter.typeError( + 6189_error, _functionCallOptions.location(), "Cannot set option \"value\" for delegatecall." ); else if (kind == FunctionType::Kind::BareStaticCall) m_errorReporter.typeError( + 2842_error, _functionCallOptions.location(), "Cannot set option \"value\" for staticcall." ); else if (!expressionFunctionType->isPayable()) m_errorReporter.typeError( + 7006_error, _functionCallOptions.location(), kind == FunctionType::Kind::Creation ? "Cannot set option \"value\", since the constructor of " + @@ -2324,6 +2405,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) { if (kind == FunctionType::Kind::Creation) m_errorReporter.typeError( + 9903_error, _functionCallOptions.location(), "Function call option \"gas\" cannot be used with \"new\"." ); @@ -2336,6 +2418,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) } else m_errorReporter.typeError( + 9318_error, _functionCallOptions.location(), "Unknown call option \"" + name + "\". Valid options are \"salt\", \"value\" and \"gas\"." ); @@ -2343,6 +2426,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) if (setSalt && !m_evmVersion.hasCreate2()) m_errorReporter.typeError( + 5189_error, _functionCallOptions.location(), "Unsupported call option \"salt\" (requires Constantinople-compatible VMs)." ); @@ -2361,13 +2445,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) auto contract = dynamic_cast(&dereference(*contractName)); if (!contract) - m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract."); + m_errorReporter.fatalTypeError(5540_error, _newExpression.location(), "Identifier is not a contract."); if (contract->isInterface()) - m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface."); + m_errorReporter.fatalTypeError(2971_error, _newExpression.location(), "Cannot instantiate an interface."); if (!contract->constructorIsPublic()) - m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly."); + m_errorReporter.typeError(9054_error, _newExpression.location(), "Contract with internal constructor cannot be created directly."); if (contract->abstract()) - m_errorReporter.typeError(_newExpression.location(), "Cannot instantiate an abstract contract."); + m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract."); solAssert(!!m_scope, ""); m_scope->annotation().contractDependencies.insert(contract); @@ -2377,6 +2461,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) ); if (contractDependenciesAreCyclic(*m_scope)) m_errorReporter.typeError( + 4579_error, _newExpression.location(), "Circular reference for contract creation (cannot create instance of derived or same contract)." ); @@ -2387,11 +2472,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) { if (!type->canLiveOutsideStorage()) m_errorReporter.fatalTypeError( + 1164_error, _newExpression.typeName().location(), "Type cannot live outside storage." ); if (!type->isDynamicallySized()) m_errorReporter.typeError( + 3904_error, _newExpression.typeName().location(), "Length has to be placed in parentheses after the array type for new expression." ); @@ -2408,7 +2495,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) _newExpression.annotation().isPure = true; } else - m_errorReporter.fatalTypeError(_newExpression.location(), "Contract or array type expected."); + m_errorReporter.fatalTypeError(8807_error, _newExpression.location(), "Contract or array type expected."); } bool TypeChecker::visit(MemberAccess const& _memberAccess) @@ -2447,6 +2534,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ); if (!storageType->members(m_scope).membersByName(memberName).empty()) m_errorReporter.fatalTypeError( + 4994_error, _memberAccess.location(), "Member \"" + memberName + "\" is not available in " + exprType->toString() + @@ -2505,12 +2593,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) } m_errorReporter.fatalTypeError( + 4035_error, _memberAccess.location(), errorMsg ); } else if (possibleMembers.size() > 1) m_errorReporter.fatalTypeError( + 6675_error, _memberAccess.location(), "Member \"" + memberName + "\" not unique " "after argument-dependent lookup in " + exprType->toString() + @@ -2534,6 +2624,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) (memberName == "value" || memberName == "gas") ) m_errorReporter.warning( + 1621_error, _memberAccess.location(), "Using \"." + memberName + "(...)\" is deprecated. Use \"{" + memberName + ": ...}\" instead." ); @@ -2587,11 +2678,22 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) )) { annotation.isPure = true; - m_scope->annotation().contractDependencies.insert( - &dynamic_cast(*magicType->typeArgument()).contractDefinition() - ); + ContractType const& accessedContractType = dynamic_cast(*magicType->typeArgument()); + m_scope->annotation().contractDependencies.insert(&accessedContractType.contractDefinition()); + + if ( + memberName == "runtimeCode" && + !accessedContractType.immutableVariables().empty() + ) + m_errorReporter.typeError( + 9274_error, + _memberAccess.location(), + "\"runtimeCode\" is not available for contracts containing immutable variables." + ); + if (contractDependenciesAreCyclic(*m_scope)) m_errorReporter.typeError( + 4224_error, _memberAccess.location(), "Circular reference for contract code access." ); @@ -2600,6 +2702,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.isPure = true; else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId") annotation.isPure = true; + else if ( + magicType->kind() == MagicType::Kind::MetaType && + (memberName == "min" || memberName == "max") + ) + annotation.isPure = true; } return false; @@ -2619,7 +2726,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { auto const& arrayType = dynamic_cast(*baseType).arrayType(); if (arrayType.location() != DataLocation::CallData || !arrayType.isDynamicallySized()) - m_errorReporter.typeError(_access.location(), "Index access is only implemented for slices of dynamic calldata arrays."); + m_errorReporter.typeError(4802_error, _access.location(), "Index access is only implemented for slices of dynamic calldata arrays."); baseType = &arrayType; [[fallthrough]]; } @@ -2627,10 +2734,10 @@ bool TypeChecker::visit(IndexAccess const& _access) { ArrayType const& actualType = dynamic_cast(*baseType); if (!index) - m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted."); + m_errorReporter.typeError(9689_error, _access.location(), "Index expression cannot be omitted."); else if (actualType.isString()) { - m_errorReporter.typeError(_access.location(), "Index access for string is not possible."); + m_errorReporter.typeError(9961_error, _access.location(), "Index access for string is not possible."); index->accept(*this); } else @@ -2641,7 +2748,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { solAssert(!numberType->isFractional(), ""); if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr)) - m_errorReporter.typeError(_access.location(), "Out of bounds array access."); + m_errorReporter.typeError(3383_error, _access.location(), "Out of bounds array access."); } } resultType = actualType.baseType(); @@ -2652,7 +2759,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { MappingType const& actualType = dynamic_cast(*baseType); if (!index) - m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted."); + m_errorReporter.typeError(1267_error, _access.location(), "Index expression cannot be omitted."); else expectType(*index, *actualType.keyType()); resultType = actualType.valueType(); @@ -2663,7 +2770,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { TypeType const& typeType = dynamic_cast(*baseType); if (dynamic_cast(typeType.actualType())) - m_errorReporter.typeError(_access.location(), "Index access for contracts or libraries is not possible."); + m_errorReporter.typeError(2876_error, _access.location(), "Index access for contracts or libraries is not possible."); if (!index) resultType = TypeProvider::typeType(TypeProvider::array(DataLocation::Memory, typeType.actualType())); else @@ -2674,7 +2781,7 @@ bool TypeChecker::visit(IndexAccess const& _access) if (auto indexValue = dynamic_cast(type(*index))) length = indexValue->literalValue(nullptr); else - m_errorReporter.fatalTypeError(index->location(), "Integer constant expected."); + m_errorReporter.fatalTypeError(3940_error, index->location(), "Integer constant expected."); } else solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false"); @@ -2691,14 +2798,14 @@ bool TypeChecker::visit(IndexAccess const& _access) { FixedBytesType const& bytesType = dynamic_cast(*baseType); if (!index) - m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted."); + m_errorReporter.typeError(8830_error, _access.location(), "Index expression cannot be omitted."); else { if (!expectType(*index, *TypeProvider::uint256())) - m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer."); + m_errorReporter.fatalTypeError(6318_error, _access.location(), "Index expression cannot be represented as an unsigned integer."); if (auto integerType = dynamic_cast(type(*index))) if (bytesType.numBytes() <= integerType->literalValue(nullptr)) - m_errorReporter.typeError(_access.location(), "Out of bounds array access."); + m_errorReporter.typeError(1859_error, _access.location(), "Out of bounds array access."); } resultType = TypeProvider::fixedBytes(1); isLValue = false; // @todo this heavily depends on how it is embedded @@ -2706,6 +2813,7 @@ bool TypeChecker::visit(IndexAccess const& _access) } default: m_errorReporter.fatalTypeError( + 2614_error, _access.baseExpression().location(), "Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")" ); @@ -2742,7 +2850,7 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) TypePointer exprType = type(_access.baseExpression()); if (exprType->category() == Type::Category::TypeType) { - m_errorReporter.typeError(_access.location(), "Types cannot be sliced."); + m_errorReporter.typeError(1760_error, _access.location(), "Types cannot be sliced."); _access.annotation().type = exprType; return false; } @@ -2751,11 +2859,13 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) if (auto const* arraySlice = dynamic_cast(exprType)) arrayType = &arraySlice->arrayType(); else if (!(arrayType = dynamic_cast(exprType))) - m_errorReporter.fatalTypeError(_access.location(), "Index range access is only possible for arrays and array slices."); + m_errorReporter.fatalTypeError(4781_error, _access.location(), "Index range access is only possible for arrays and array slices."); if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized()) - m_errorReporter.typeError(_access.location(), "Index range access is only supported for dynamic calldata arrays."); + m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays."); + else if (arrayType->baseType()->isDynamicallyEncoded()) + m_errorReporter.typeError(1878_error, _access.location(), "Index range access is not supported for arrays with dynamically encoded base types."); _access.annotation().type = TypeProvider::arraySlice(*arrayType); _access.annotation().isLValue = isLValue; _access.annotation().isPure = isPure; @@ -2790,7 +2900,7 @@ vector TypeChecker::cleanOverloadedDeclarations( for (TypePointer parameter: functionType->parameterTypes() + functionType->returnParameterTypes()) if (!parameter) - m_errorReporter.fatalDeclarationError(_identifier.location(), "Function type can not be used in this context."); + m_errorReporter.fatalDeclarationError(3893_error, _identifier.location(), "Function type can not be used in this context."); if (uniqueDeclarations.end() == find_if( uniqueDeclarations.begin(), @@ -2825,14 +2935,14 @@ bool TypeChecker::visit(Identifier const& _identifier) candidates.push_back(declaration); } if (candidates.empty()) - m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after variable lookup."); + m_errorReporter.fatalTypeError(2144_error, _identifier.location(), "No matching declaration found after variable lookup."); else if (candidates.size() == 1) annotation.referencedDeclaration = candidates.front(); else - m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after variable lookup."); + m_errorReporter.fatalTypeError(7589_error, _identifier.location(), "No unique declaration found after variable lookup."); } else if (annotation.overloadedDeclarations.empty()) - m_errorReporter.fatalTypeError(_identifier.location(), "No candidates for overload resolution found."); + m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found."); else if (annotation.overloadedDeclarations.size() == 1) annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin(); else @@ -2866,9 +2976,9 @@ bool TypeChecker::visit(Identifier const& _identifier) else ssl.append("Candidate:", declaration->location()); if (candidates.empty()) - m_errorReporter.fatalTypeError(_identifier.location(), ssl, "No matching declaration found after argument-dependent lookup."); + m_errorReporter.fatalTypeError(9322_error, _identifier.location(), ssl, "No matching declaration found after argument-dependent lookup."); else - m_errorReporter.fatalTypeError(_identifier.location(), ssl, "No unique declaration found after argument-dependent lookup."); + m_errorReporter.fatalTypeError(4487_error, _identifier.location(), ssl, "No unique declaration found after argument-dependent lookup."); } } } @@ -2896,11 +3006,13 @@ bool TypeChecker::visit(Identifier const& _identifier) { if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256) m_errorReporter.typeError( + 3557_error, _identifier.location(), "\"sha3\" has been deprecated in favour of \"keccak256\"." ); else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct) m_errorReporter.typeError( + 8050_error, _identifier.location(), "\"suicide\" has been deprecated in favour of \"selfdestruct\"." ); @@ -2938,6 +3050,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (!msg.empty()) m_errorReporter.syntaxError( + 9429_error, _literal.location(), msg + " If this is not used as an address, please prepend '00'. " + @@ -2947,6 +3060,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (_literal.isHexNumber() && _literal.subDenomination() != Literal::SubDenomination::None) m_errorReporter.fatalTypeError( + 5145_error, _literal.location(), "Hexadecimal numbers cannot be used with unit denominations. " "You can use an expression of the form \"0x1234 * 1 day\" instead." @@ -2954,6 +3068,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (_literal.subDenomination() == Literal::SubDenomination::Year) m_errorReporter.typeError( + 4820_error, _literal.location(), "Using \"years\" as a unit denomination is deprecated." ); @@ -2962,7 +3077,7 @@ void TypeChecker::endVisit(Literal const& _literal) _literal.annotation().type = TypeProvider::forLiteral(_literal); if (!_literal.annotation().type) - m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value."); + m_errorReporter.fatalTypeError(2826_error, _literal.location(), "Invalid literal value."); _literal.annotation().isPure = true; } @@ -3012,11 +3127,13 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte { if (_expectedType.operator==(*type(_expression)->mobileType())) m_errorReporter.typeError( + 4426_error, _expression.location(), errorMsg + ", but it can be explicitly converted." ); else m_errorReporter.typeError( + 2326_error, _expression.location(), errorMsg + ". Try converting to type " + @@ -3025,7 +3142,7 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte ); } else - m_errorReporter.typeError(_expression.location(), errorMsg + "."); + m_errorReporter.typeError(7407_error, _expression.location(), errorMsg + "."); return false; } return true; @@ -3040,7 +3157,7 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss if (_expression.annotation().isLValue) return; - return m_errorReporter.typeError(_expression.location(), [&]() { + return m_errorReporter.typeError(1123_error, _expression.location(), [&]() { if (_expression.annotation().isConstant) return "Cannot assign to a constant variable."; diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 0d87fdbc2fa8..230e0a8bab56 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -171,6 +171,7 @@ void ViewPureChecker::endVisit(FunctionDefinition const& _funDef) !_funDef.overrides() ) m_errorReporter.warning( + 2018_error, _funDef.location(), "Function state mutability can be restricted to " + stateMutabilityToString(m_bestMutabilityAndLocation.mutability) ); @@ -229,7 +230,7 @@ void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly) { AssemblyViewPureChecker{ _inlineAssembly.dialect(), - [=](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); } + [&](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); } }(_inlineAssembly.operations()); } @@ -252,6 +253,7 @@ void ViewPureChecker::reportMutability( )) { m_errorReporter.typeError( + 2527_error, _location, "Function declared as pure, but this expression (potentially) reads from the " "environment or state and thus requires \"view\"." @@ -261,6 +263,7 @@ void ViewPureChecker::reportMutability( else if (_mutability == StateMutability::NonPayable) { m_errorReporter.typeError( + 8961_error, _location, "Function declared as " + stateMutabilityToString(m_currentFunction->stateMutability()) + @@ -277,12 +280,14 @@ void ViewPureChecker::reportMutability( { if (_nestedLocation) m_errorReporter.typeError( + 4006_error, _location, SecondarySourceLocation().append("\"msg.value\" or \"callvalue()\" appear here inside the modifier.", *_nestedLocation), "This modifier uses \"msg.value\" or \"callvalue()\" and thus the function has to be payable or internal." ); else m_errorReporter.typeError( + 5887_error, _location, "\"msg.value\" and \"callvalue()\" can only be used in payable public functions. Make the function " "\"payable\" or use an internal function to avoid this error." @@ -357,6 +362,8 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) {MagicType::Kind::MetaType, "runtimeCode"}, {MagicType::Kind::MetaType, "name"}, {MagicType::Kind::MetaType, "interfaceId"}, + {MagicType::Kind::MetaType, "min"}, + {MagicType::Kind::MetaType, "max"}, }; set static const payableMembers{ {MagicType::Kind::Message, "value"} diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 3c79912c2441..0c4e181e8968 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -156,19 +156,26 @@ std::vector ASTNode::filteredNodes(std::vector> co class SourceUnit: public ASTNode { public: - SourceUnit(int64_t _id, SourceLocation const& _location, std::vector> _nodes): - ASTNode(_id, _location), m_nodes(std::move(_nodes)) {} + SourceUnit( + int64_t _id, + SourceLocation const& _location, + std::optional _licenseString, + std::vector> _nodes + ): + ASTNode(_id, _location), m_licenseString(std::move(_licenseString)), m_nodes(std::move(_nodes)) {} void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; SourceUnitAnnotation& annotation() const override; + std::optional const& licenseString() const { return m_licenseString; } std::vector> nodes() const { return m_nodes; } /// @returns a set of referenced SourceUnits. Recursively if @a _recurse is true. std::set referencedSourceUnits(bool _recurse = false, std::set _skipList = std::set()) const; private: + std::optional m_licenseString; std::vector> m_nodes; }; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 9f61184bea40..603781b26644 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -225,6 +225,7 @@ bool ASTJsonConverter::visit(SourceUnit const& _node) { make_pair("absolutePath", _node.annotation().path), make_pair("exportedSymbols", move(exportedSymbols)), + make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue), make_pair("nodes", toJson(_node.nodes())) } ); diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index e4538059d2fd..c0bee4c60ceb 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -218,10 +218,15 @@ ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js ASTPointer ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName) { + optional license; + if (_node.isMember("license") && !_node["license"].isNull()) + license = _node["license"].asString(); + vector> nodes; for (auto& child: member(_node, "nodes")) nodes.emplace_back(convertJsonToASTNode(child)); - ASTPointer tmp = createASTNode(_node, nodes); + + ASTPointer tmp = createASTNode(_node, license, nodes); tmp->annotation().path = _srcName; return tmp; } diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index 7dd895cbe579..6fd7784031f3 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -556,7 +556,13 @@ MagicType const* TypeProvider::magic(MagicType::Kind _kind) MagicType const* TypeProvider::meta(Type const* _type) { - solAssert(_type && _type->category() == Type::Category::Contract, "Only contracts supported for now."); + solAssert( + _type && ( + _type->category() == Type::Category::Contract || + _type->category() == Type::Category::Integer + ), + "Only contracts or integer types supported for now." + ); return createAndGet(_type); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 7ee12d6dd682..b19ab4c4bbb5 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -330,7 +330,7 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c // Structs are fine in the following circumstances: // - ABIv2 or, // - storage struct for a library - if (_inLibraryCall && encodingType->dataStoredIn(DataLocation::Storage)) + if (_inLibraryCall && encodingType && encodingType->dataStoredIn(DataLocation::Storage)) return encodingType; TypePointer baseType = encodingType; while (auto const* arrayType = dynamic_cast(baseType)) @@ -556,6 +556,22 @@ string IntegerType::toString(bool) const return prefix + util::toString(m_bits); } +u256 IntegerType::min() const +{ + if (isSigned()) + return s2u(s256(minValue())); + else + return u256(minValue()); +} + +u256 IntegerType::max() const +{ + if (isSigned()) + return s2u(s256(maxValue())); + else + return u256(maxValue()); +} + bigint IntegerType::minValue() const { if (isSigned()) @@ -597,6 +613,13 @@ TypeResult IntegerType::binaryOperatorResult(Token _operator, Type const* _other } else if (dynamic_cast(_other)) return nullptr; + else if (auto rationalNumberType = dynamic_cast(_other)) + { + if (rationalNumberType->isFractional()) + return TypeResult::err("Exponent is fractional."); + if (!rationalNumberType->integerType()) + return TypeResult::err("Exponent too large."); + } return this; } @@ -1948,6 +1971,19 @@ string ArraySliceType::toString(bool _short) const return m_arrayType.toString(_short) + " slice"; } +TypePointer ArraySliceType::mobileType() const +{ + if ( + m_arrayType.dataStoredIn(DataLocation::CallData) && + m_arrayType.isDynamicallySized() && + !m_arrayType.baseType()->isDynamicallyEncoded() + ) + return &m_arrayType; + else + return this; +} + + std::vector> ArraySliceType::makeStackItems() const { return {{"offset", TypeProvider::uint256()}, {"length", TypeProvider::uint256()}}; @@ -3763,20 +3799,35 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const case Kind::MetaType: { solAssert( - m_typeArgument && m_typeArgument->category() == Type::Category::Contract, - "Only contracts supported for now" + m_typeArgument && ( + m_typeArgument->category() == Type::Category::Contract || + m_typeArgument->category() == Type::Category::Integer + ), + "Only contracts or integer types supported for now" ); - ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); - if (contract.canBeDeployed()) - return MemberList::MemberMap({ - {"creationCode", TypeProvider::array(DataLocation::Memory)}, - {"runtimeCode", TypeProvider::array(DataLocation::Memory)}, - {"name", TypeProvider::stringMemory()}, - }); - else + + if (m_typeArgument->category() == Type::Category::Contract) + { + ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); + if (contract.canBeDeployed()) + return MemberList::MemberMap({ + {"creationCode", TypeProvider::array(DataLocation::Memory)}, + {"runtimeCode", TypeProvider::array(DataLocation::Memory)}, + {"name", TypeProvider::stringMemory()}, + }); + else + return MemberList::MemberMap({ + {"interfaceId", TypeProvider::fixedBytes(4)}, + }); + } + else if (m_typeArgument->category() == Type::Category::Integer) + { + IntegerType const* integerTypePointer = dynamic_cast(m_typeArgument); return MemberList::MemberMap({ - {"interfaceId", TypeProvider::fixedBytes(4)}, + {"min", integerTypePointer}, + {"max", integerTypePointer}, }); + } } } solAssert(false, "Unknown kind of magic."); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 974bae4a3978..11e948f265df 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -452,6 +452,9 @@ class IntegerType: public Type unsigned numBits() const { return m_bits; } bool isSigned() const { return m_modifier == Modifier::Signed; } + u256 min() const; + u256 max() const; + bigint minValue() const; bigint maxValue() const; @@ -828,6 +831,7 @@ class ArraySliceType: public ReferenceType bool isDynamicallyEncoded() const override { return true; } bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); } std::string toString(bool _short) const override; + TypePointer mobileType() const override; BoolResult validForLocation(DataLocation _loc) const override { return m_arrayType.validForLocation(_loc); } diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 8909651be0e0..189fba165c8b 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -28,7 +28,6 @@ #include #include -#include using namespace std; using namespace solidity; @@ -38,7 +37,8 @@ using namespace solidity::frontend; string ABIFunctions::tupleEncoder( TypePointers const& _givenTypes, TypePointers const& _targetTypes, - bool _encodeAsLibraryTypes + bool _encodeAsLibraryTypes, + bool _reversed ) { EncodingOptions options; @@ -54,6 +54,8 @@ string ABIFunctions::tupleEncoder( for (auto const& t: _targetTypes) functionName += t->identifier() + "_"; functionName += options.toFunctionNameSuffix(); + if (_reversed) + functionName += "_reversed"; return createFunction(functionName, [&]() { // Note that the values are in reverse due to the difference in calling semantics. @@ -94,7 +96,10 @@ string ABIFunctions::tupleEncoder( stackPos += sizeOnStack; } solAssert(headPos == headSize_, ""); - string valueParams = suffixedVariableNameList("value", stackPos, 0); + string valueParams = + _reversed ? + suffixedVariableNameList("value", stackPos, 0) : + suffixedVariableNameList("value", 0, stackPos); templ("valueParams", valueParams.empty() ? "" : ", " + valueParams); templ("encodeElements", encodeElements); @@ -104,7 +109,8 @@ string ABIFunctions::tupleEncoder( string ABIFunctions::tupleEncoderPacked( TypePointers const& _givenTypes, - TypePointers const& _targetTypes + TypePointers const& _targetTypes, + bool _reversed ) { EncodingOptions options; @@ -120,6 +126,8 @@ string ABIFunctions::tupleEncoderPacked( for (auto const& t: _targetTypes) functionName += t->identifier() + "_"; functionName += options.toFunctionNameSuffix(); + if (_reversed) + functionName += "_reversed"; return createFunction(functionName, [&]() { solAssert(!_givenTypes.empty(), ""); @@ -158,7 +166,10 @@ string ABIFunctions::tupleEncoderPacked( encodeElements += elementTempl.render(); stackPos += sizeOnStack; } - string valueParams = suffixedVariableNameList("value", stackPos, 0); + string valueParams = + _reversed ? + suffixedVariableNameList("value", stackPos, 0) : + suffixedVariableNameList("value", 0, stackPos); templ("valueParams", valueParams.empty() ? "" : ", " + valueParams); templ("encodeElements", encodeElements); @@ -268,31 +279,47 @@ string ABIFunctions::abiEncodingFunction( return abiEncodingFunctionStringLiteral(_from, to, _options); else if (auto toArray = dynamic_cast(&to)) { - solAssert(_from.category() == Type::Category::Array, ""); - solAssert(to.dataStoredIn(DataLocation::Memory), ""); - ArrayType const& fromArray = dynamic_cast(_from); + ArrayType const* fromArray = nullptr; + switch (_from.category()) + { + case Type::Category::Array: + fromArray = dynamic_cast(&_from); + break; + case Type::Category::ArraySlice: + fromArray = &dynamic_cast(&_from)->arrayType(); + solAssert( + fromArray->dataStoredIn(DataLocation::CallData) && + fromArray->isDynamicallySized() && + !fromArray->baseType()->isDynamicallyEncoded(), + "" + ); + break; + default: + solAssert(false, ""); + break; + } - switch (fromArray.location()) + switch (fromArray->location()) { case DataLocation::CallData: if ( - fromArray.isByteArray() || - *fromArray.baseType() == *TypeProvider::uint256() || - *fromArray.baseType() == FixedBytesType(32) + fromArray->isByteArray() || + *fromArray->baseType() == *TypeProvider::uint256() || + *fromArray->baseType() == FixedBytesType(32) ) - return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options); + return abiEncodingFunctionCalldataArrayWithoutCleanup(*fromArray, *toArray, _options); else - return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); case DataLocation::Memory: - if (fromArray.isByteArray()) - return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options); + if (fromArray->isByteArray()) + return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options); else - return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); case DataLocation::Storage: - if (fromArray.baseType()->storageBytes() <= 16) - return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options); + if (fromArray->baseType()->storageBytes() <= 16) + return abiEncodingFunctionCompactStorageArray(*fromArray, *toArray, _options); else - return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); default: solAssert(false, ""); } diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index e760917ac619..a66b1284e931 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -67,31 +67,53 @@ class ABIFunctions /// @returns name of an assembly function to ABI-encode values of @a _givenTypes /// into memory, converting the types to @a _targetTypes on the fly. - /// Parameters are: ... , i.e. - /// the layout on the stack is ... with + /// Parameters are: ... , i.e. + /// the layout on the stack is ... with /// the top of the stack on the right. /// The values represent stack slots. If a type occupies more or less than one /// stack slot, it takes exactly that number of values. /// Returns a pointer to the end of the area written in memory. /// Does not allocate memory (does not change the free memory pointer), but writes /// to memory starting at $headStart and an unrestricted amount after that. + /// If @reversed is true, the order of the variables after is reversed. std::string tupleEncoder( TypePointers const& _givenTypes, TypePointers const& _targetTypes, - bool _encodeAsLibraryTypes = false + bool _encodeAsLibraryTypes = false, + bool _reversed = false ); + /// Specialization of tupleEncoder to _reversed = true + std::string tupleEncoderReversed( + TypePointers const& _givenTypes, + TypePointers const& _targetTypes, + bool _encodeAsLibraryTypes = false + ) { + return tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes, true); + } + /// @returns name of an assembly function to encode values of @a _givenTypes /// with packed encoding into memory, converting the types to @a _targetTypes on the fly. - /// Parameters are: ... , i.e. - /// the layout on the stack is ... with + /// Parameters are: ... , i.e. + /// the layout on the stack is ... with /// the top of the stack on the right. /// The values represent stack slots. If a type occupies more or less than one /// stack slot, it takes exactly that number of values. /// Returns a pointer to the end of the area written in memory. /// Does not allocate memory (does not change the free memory pointer), but writes /// to memory starting at memPos and an unrestricted amount after that. - std::string tupleEncoderPacked(TypePointers const& _givenTypes, TypePointers const& _targetTypes); + /// If @reversed is true, the order of the variables after is reversed. + std::string tupleEncoderPacked( + TypePointers const& _givenTypes, + TypePointers const& _targetTypes, + bool _reversed = false + ); + + /// Specialization of tupleEncoderPacked to _reversed = true + std::string tupleEncoderPackedReversed(TypePointers const& _givenTypes, TypePointers const& _targetTypes) + { + return tupleEncoderPacked(_givenTypes, _targetTypes, true); + } /// @returns name of an assembly function to ABI-decode values of @a _types /// into memory. If @a _fromMemory is true, decodes from memory instead of diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 78198fff038e..f343f2377596 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -49,6 +49,9 @@ void Compiler::compileContract( m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers); m_context.optimise(m_optimiserSettings); + + solAssert(m_context.requestedYulFunctionsRan(), "requestedYulFunctions() was not called."); + solAssert(m_runtimeContext.requestedYulFunctionsRan(), "requestedYulFunctions() was not called."); } std::shared_ptr Compiler::runtimeAssemblyPtr() const diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 2d81e833b432..9431ecec6a61 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -192,6 +192,9 @@ void CompilerContext::appendMissingLowLevelFunctions() pair> CompilerContext::requestedYulFunctions() { + solAssert(!m_requestedYulFunctionsRan, "requestedYulFunctions called more than once."); + m_requestedYulFunctionsRan = true; + set empty; swap(empty, m_externallyUsedYulFunctions); return {m_yulFunctionCollector.requestedFunctions(), std::move(empty)}; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 0720a8f3b0d5..51d3afe1c1b5 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -167,6 +167,7 @@ class CompilerContext /// Clears the internal list, i.e. calling it again will result in an /// empty return value. std::pair> requestedYulFunctions(); + bool requestedYulFunctionsRan() const { return m_requestedYulFunctionsRan; } /// Returns the distance of the given local variable from the bottom of the stack (of the current function). unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; @@ -389,6 +390,8 @@ class CompilerContext YulUtilFunctions m_yulUtilFunctions; /// The queue of low-level functions to generate. std::queue>> m_lowLevelFunctionGenerationQueue; + /// Flag to check that requestedYulFunctions() was called exactly once + bool m_requestedYulFunctionsRan = false; }; } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 3d0117707b47..8bf0a21e2101 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -480,6 +480,16 @@ void CompilerUtils::encodeToMemory( convertType(*_givenTypes[i], *targetType, true); if (auto arrayType = dynamic_cast(type)) ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries); + else if (auto arraySliceType = dynamic_cast(type)) + { + solAssert( + arraySliceType->dataStoredIn(DataLocation::CallData) && + arraySliceType->isDynamicallySized() && + !arraySliceType->arrayType().baseType()->isDynamicallyEncoded(), + "" + ); + ArrayUtils(m_context).copyArrayToMemory(arraySliceType->arrayType(), _padToWordBoundaries); + } else storeInMemoryDynamic(*type, _padToWordBoundaries); } @@ -516,22 +526,39 @@ void CompilerUtils::encodeToMemory( } else { - solAssert(_givenTypes[i]->category() == Type::Category::Array, "Unknown dynamic type."); - auto const& arrayType = dynamic_cast(*_givenTypes[i]); + ArrayType const* arrayType = nullptr; + switch (_givenTypes[i]->category()) + { + case Type::Category::Array: + arrayType = dynamic_cast(_givenTypes[i]); + break; + case Type::Category::ArraySlice: + arrayType = &dynamic_cast(_givenTypes[i])->arrayType(); + solAssert( + arrayType->isDynamicallySized() && + arrayType->dataStoredIn(DataLocation::CallData) && + !arrayType->baseType()->isDynamicallyEncoded(), + "" + ); + break; + default: + solAssert(false, "Unknown dynamic type."); + break; + } // now copy the array - copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.sizeOnStack()); + copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType->sizeOnStack()); // stack: ... // copy length to memory - m_context << dupInstruction(1 + arrayType.sizeOnStack()); - ArrayUtils(m_context).retrieveLength(arrayType, 1); + m_context << dupInstruction(1 + arrayType->sizeOnStack()); + ArrayUtils(m_context).retrieveLength(*arrayType, 1); // stack: ... storeInMemoryDynamic(*TypeProvider::uint256(), true); // stack: ... // copy the new memory pointer - m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP; + m_context << swapInstruction(arrayType->sizeOnStack() + 1) << Instruction::POP; // stack: ... // copy data part - ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries); + ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries); // stack: ... } @@ -559,8 +586,8 @@ void CompilerUtils::abiEncodeV2( string encoderName = _padToWordBoundaries ? - m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : - m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes); + m_context.abiFunctions().tupleEncoderReversed(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : + m_context.abiFunctions().tupleEncoderPackedReversed(_givenTypes, _targetTypes); m_context.callYulFunction(encoderName, sizeOnStack(_givenTypes) + 1, 1); } @@ -990,7 +1017,8 @@ void CompilerUtils::convertType( solAssert(_targetType == typeOnStack.arrayType(), ""); solUnimplementedAssert( typeOnStack.arrayType().location() == DataLocation::CallData && - typeOnStack.arrayType().isDynamicallySized(), + typeOnStack.arrayType().isDynamicallySized() && + !typeOnStack.arrayType().baseType()->isDynamicallyEncoded(), "" ); break; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index d095c1eac6f8..269d9a5bf3e0 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -103,8 +103,6 @@ void ContractCompiler::compileContract( // and adds the function to the compilation queue. Additionally internal functions, // which are referenced directly or indirectly will be added. appendFunctionSelector(_contract); - // This processes the above populated queue until it is empty. - appendMissingFunctions(); } size_t ContractCompiler::compileConstructor( @@ -159,10 +157,13 @@ void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _c if (FunctionDefinition const* constructor = _contract.constructor()) appendConstructor(*constructor); - else if (auto c = _contract.nextConstructor(m_context.mostDerivedContract())) - appendBaseConstructor(*c); else + { + // Implicit constructors are always non-payable. appendCallValueCheck(); + if (auto c = _contract.nextConstructor(m_context.mostDerivedContract())) + appendBaseConstructor(*c); + } } size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _contract) @@ -215,6 +216,9 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) solAssert(!!m_runtimeCompiler, ""); solAssert(_contract.isLibrary(), "Tried to deploy contract as library."); + appendMissingFunctions(); + m_runtimeCompiler->appendMissingFunctions(); + CompilerContext::LocationSetter locationSetter(m_context, _contract); solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); @@ -586,13 +590,13 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) if (!_function.isConstructor()) // adding 1 for return address. m_context.adjustStackOffset(parametersSize + 1); - for (ASTPointer const& variable: _function.parameters()) + for (ASTPointer const& variable: _function.parameters()) { m_context.addVariable(*variable, parametersSize); parametersSize -= variable->annotation().type->sizeOnStack(); } - for (ASTPointer const& variable: _function.returnParameters()) + for (ASTPointer const& variable: _function.returnParameters()) appendStackVariableInitialisation(*variable); if (_function.isConstructor()) @@ -649,7 +653,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) if (stackLayout[i] != i) solAssert(false, "Invalid stack layout on cleanup."); - for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) + for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) m_context.removeVariable(*variable); m_context.adjustStackOffset(-(int)c_returnValuesSize); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 14b0d763b781..f05ffda8f170 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -36,7 +36,6 @@ #include #include -#include #include #include @@ -1591,6 +1590,16 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) result ^= fromBigEndian(function.first.ref()); m_context << (u256{result} << (256 - 32)); } + else if (member == "min" || member == "max") + { + MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); + IntegerType const* integerType = dynamic_cast(arg->typeArgument()); + + if (member == "min") + m_context << integerType->min(); + else + m_context << integerType->max(); + } else if ((set{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member)) { // no-op @@ -1760,7 +1769,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) case Type::Category::ArraySlice: { auto const& arrayType = dynamic_cast(baseType).arrayType(); - solAssert(arrayType.location() == DataLocation::CallData && arrayType.isDynamicallySized(), ""); + solAssert( + arrayType.location() == DataLocation::CallData && + arrayType.isDynamicallySized() && + !arrayType.baseType()->isDynamicallyEncoded(), + "" + ); solAssert(_indexAccess.indexExpression(), "Index expression expected."); acceptAndConvert(*_indexAccess.indexExpression(), *TypeProvider::uint256(), true); @@ -1843,7 +1857,12 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) arrayType = &sliceType->arrayType(); solAssert(arrayType, ""); - solUnimplementedAssert(arrayType->location() == DataLocation::CallData && arrayType->isDynamicallySized(), ""); + solUnimplementedAssert( + arrayType->location() == DataLocation::CallData && + arrayType->isDynamicallySized() && + !arrayType->baseType()->isDynamicallyEncoded(), + "" + ); if (_indexAccess.startExpression()) acceptAndConvert(*_indexAccess.startExpression(), *TypeProvider::uint256()); diff --git a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp index e8994ac04bc3..f49f3083d37a 100644 --- a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp +++ b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp @@ -23,8 +23,6 @@ #include -#include -#include using namespace std; using namespace solidity; diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 75d297b3474f..4fd681e1fbf2 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -28,9 +28,6 @@ #include #include -#include -#include - using namespace std; using namespace solidity; using namespace solidity::util; @@ -299,9 +296,6 @@ string YulUtilFunctions::shiftRightFunction(size_t _numBits) string YulUtilFunctions::shiftRightFunctionDynamic() { - // Note that if this is extended with signed shifts, - // the opcodes SAR and SDIV behave differently with regards to rounding! - string const functionName = "shift_right_unsigned_dynamic"; return m_functionCollector.createFunction(functionName, [&]() { return @@ -321,6 +315,86 @@ string YulUtilFunctions::shiftRightFunctionDynamic() }); } +string YulUtilFunctions::shiftRightSignedFunctionDynamic() +{ + string const functionName = "shift_right_signed_dynamic"; + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (bits, value) -> result { + + result := sar(bits, value) + + let divisor := exp(2, bits) + let xor_mask := sub(0, slt(value, 0)) + result := xor(div(xor(value, xor_mask), divisor), xor_mask) + // combined version of + // switch slt(value, 0) + // case 0 { result := div(value, divisor) } + // default { result := not(div(not(value), divisor)) } + + } + )") + ("functionName", functionName) + ("hasShifts", m_evmVersion.hasBitwiseShifting()) + .render(); + }); +} + + +string YulUtilFunctions::typedShiftLeftFunction(Type const& _type, Type const& _amountType) +{ + solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, ""); + solAssert(_amountType.category() == Type::Category::Integer, ""); + string const functionName = "shift_left_" + _type.identifier() + "_" + _amountType.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (value, bits) -> result { + bits := (bits) + + if slt(bits, 0) { invalid() } + + result := ((bits, value)) + } + )") + ("functionName", functionName) + ("amountSigned", dynamic_cast(_amountType).isSigned()) + ("cleanAmount", cleanupFunction(_amountType)) + ("shift", shiftLeftFunctionDynamic()) + ("cleanup", cleanupFunction(_type)) + .render(); + }); +} + +string YulUtilFunctions::typedShiftRightFunction(Type const& _type, Type const& _amountType) +{ + solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, ""); + solAssert(_amountType.category() == Type::Category::Integer, ""); + IntegerType const* integerType = dynamic_cast(&_type); + bool valueSigned = integerType && integerType->isSigned(); + + string const functionName = "shift_right_" + _type.identifier() + "_" + _amountType.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (value, bits) -> result { + bits := (bits) + + if slt(bits, 0) { invalid() } + + result := ((bits, (value))) + } + )") + ("functionName", functionName) + ("amountSigned", dynamic_cast(_amountType).isSigned()) + ("cleanAmount", cleanupFunction(_amountType)) + ("shift", valueSigned ? shiftRightSignedFunctionDynamic() : shiftRightFunctionDynamic()) + ("cleanup", cleanupFunction(_type)) + .render(); + }); +} + string YulUtilFunctions::updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes) { solAssert(_numBytes <= 32, ""); @@ -393,6 +467,8 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> sum { + x := (x) + y := (y) // overflow, if x >= 0 and y > (maxValue - x) if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { revert(0, 0) } @@ -409,6 +485,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -421,6 +498,8 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) // Multiplication by zero could be treated separately and directly return zero. Whiskers(R"( function (x, y) -> product { + x := (x) + y := (y) // overflow, if x > 0, y > 0 and x > (maxValue / y) if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { revert(0, 0) } @@ -441,6 +520,7 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -452,6 +532,8 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> r { + x := (x) + y := (y) if iszero(y) { revert(0, 0) } // overflow for minVal / -1 @@ -466,6 +548,7 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) ("functionName", functionName) ("signed", _type.isSigned()) ("minVal", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -477,12 +560,15 @@ string YulUtilFunctions::checkedIntModFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> r { + x := (x) + y := (y) if iszero(y) { revert(0, 0) } r := smod(x, y) } )") ("functionName", functionName) ("signed", _type.isSigned()) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -494,6 +580,8 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> diff { + x := (x) + y := (y) // underflow, if y >= 0 and x < (minValue + y) if and(iszero(slt(y, 0)), slt(x, add(, y))) { revert(0, 0) } @@ -509,6 +597,7 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -1033,13 +1122,12 @@ string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingT return m_functionCollector.createFunction(functionName, [&]() { if (_mappingType.keyType()->isDynamicallySized()) return Whiskers(R"( - function (slot ) -> dataSlot { - dataSlot := (slot ) + function (slot , ) -> dataSlot { + dataSlot := ( , slot) } )") ("functionName", functionName) ("key", _keyType.sizeOnStack() > 0 ? "key" : "") - ("comma", _keyType.sizeOnStack() > 0 ? "," : "") ("hash", packedHashFunction( {&_keyType, TypeProvider::uint256()}, {_mappingType.keyType(), TypeProvider::uint256()} @@ -1511,6 +1599,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) ArraySliceType const& fromType = dynamic_cast(_from); ArrayType const& targetType = dynamic_cast(_to); + solAssert(!fromType.arrayType().baseType()->isDynamicallyEncoded(), ""); solAssert( *fromType.arrayType().baseType() == *targetType.baseType(), "Converting arrays of different type is not possible" @@ -1764,8 +1853,18 @@ string YulUtilFunctions::cleanupFunction(Type const& _type) solUnimplemented("Fixed point types not implemented."); break; case Type::Category::Function: - solAssert(dynamic_cast(_type).kind() == FunctionType::Kind::External, ""); - templ("body", "cleaned := " + cleanupFunction(FixedBytesType(24)) + "(value)"); + switch (dynamic_cast(_type).kind()) + { + case FunctionType::Kind::External: + templ("body", "cleaned := " + cleanupFunction(FixedBytesType(24)) + "(value)"); + break; + case FunctionType::Kind::Internal: + templ("body", "cleaned := value"); + break; + default: + solAssert(false, ""); + break; + } break; case Type::Category::Array: case Type::Category::Struct: @@ -1938,14 +2037,16 @@ std::string YulUtilFunctions::decrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { + value := (value) if (value, ) { revert(0,0) } ret := sub(value, 1) } )") - ("functionName", functionName) - ("minval", toCompactHexWithPrefix(minintval)) - ("lt", type.isSigned() ? "slt" : "lt") - .render(); + ("functionName", functionName) + ("minval", toCompactHexWithPrefix(minintval)) + ("lt", type.isSigned() ? "slt" : "lt") + ("cleanupFunction", cleanupFunction(_type)) + .render(); }); } @@ -1966,14 +2067,16 @@ std::string YulUtilFunctions::incrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { + value := (value) if (value, ) { revert(0,0) } ret := add(value, 1) } )") - ("functionName", functionName) - ("maxval", toCompactHexWithPrefix(maxintval)) - ("gt", type.isSigned() ? "sgt" : "gt") - .render(); + ("functionName", functionName) + ("maxval", toCompactHexWithPrefix(maxintval)) + ("gt", type.isSigned() ? "sgt" : "gt") + ("cleanupFunction", cleanupFunction(_type)) + .render(); }); } @@ -1988,15 +2091,17 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type) return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( - function (_value) -> ret { - if slt(_value, ) { revert(0,0) } - ret := sub(0, _value) + function (value) -> ret { + value := (value) + if slt(value, ) { revert(0,0) } + ret := sub(0, value) } )") - ("functionName", functionName) - ("minval", toCompactHexWithPrefix(minintval)) - .render(); - }); + ("functionName", functionName) + ("minval", toCompactHexWithPrefix(minintval)) + ("cleanupFunction", cleanupFunction(_type)) + .render(); + }); } string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctionTypes) @@ -2214,7 +2319,6 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC } solAssert(_type.isValueType(), ""); - if (auto const* funType = dynamic_cast(&_type)) if (funType->kind() == FunctionType::Kind::External) return Whiskers(R"( @@ -2228,18 +2332,23 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC ("splitFunction", splitExternalFunctionIdFunction()) .render(); + return Whiskers(R"( - function (memPtr) -> value { - value := (memPtr) - + function (ptr) -> value { + + value := calldataload(ptr) (value) - + + value := (mload(ptr)) + } )") ("functionName", functionName) - ("load", _fromCalldata ? "calldataload" : "mload") - ("needsValidation", _fromCalldata) - ("validate", _fromCalldata ? validatorFunction(_type) : "") + ("fromCalldata", _fromCalldata) + ("validate", validatorFunction(_type)) + // Byte array elements generally need cleanup. + // Other types are cleaned as well to account for dirty memory e.g. due to inline assembly. + ("cleanup", cleanupFunction(_type)) .render(); }); } diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 4f7556f5fbb0..e72d6d29384d 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -81,6 +81,14 @@ class YulUtilFunctions std::string shiftLeftFunctionDynamic(); std::string shiftRightFunction(size_t _numBits); std::string shiftRightFunctionDynamic(); + std::string shiftRightSignedFunctionDynamic(); + + /// @returns the name of a function that performs a left shift and subsequent cleanup + /// and, if needed, prior cleanup. + /// If the amount to shift by is signed, a check for negativeness is performed. + /// signature: (value, amountToShift) -> result + std::string typedShiftLeftFunction(Type const& _type, Type const& _amountType); + std::string typedShiftRightFunction(Type const& _type, Type const& _amountType); /// @returns the name of a function which replaces the /// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant @@ -204,7 +212,7 @@ class YulUtilFunctions std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes); std::string readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes); - /// @returns a function that reads a value type from memory. + /// @returns a function that reads a value type from memory. Performs cleanup. /// signature: (addr) -> value std::string readFromMemory(Type const& _type); /// @returns a function that reads a value type from calldata. diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 43e9f95e2932..ed3b989d0ef9 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -76,6 +77,36 @@ IRVariable const& IRGenerationContext::localVariable(VariableDeclaration const& return m_localVariables.at(&_varDecl); } +void IRGenerationContext::registerImmutableVariable(VariableDeclaration const& _variable) +{ + solAssert(_variable.immutable(), "Attempted to register a non-immutable variable as immutable."); + solUnimplementedAssert( + _variable.annotation().type->isValueType(), + "Only immutable variables of value type are supported." + ); + solAssert(m_reservedMemory.has_value(), "Reserved memory has already been reset."); + m_immutableVariables[&_variable] = CompilerUtils::generalPurposeMemoryStart + *m_reservedMemory; + solAssert(_variable.annotation().type->memoryHeadSize() == 32, "Memory writes might overlap."); + *m_reservedMemory += _variable.annotation().type->memoryHeadSize(); +} + +size_t IRGenerationContext::immutableMemoryOffset(VariableDeclaration const& _variable) const +{ + solAssert( + m_immutableVariables.count(&_variable), + "Unknown immutable variable: " + _variable.name() + ); + return m_immutableVariables.at(&_variable); +} + +size_t IRGenerationContext::reservedMemory() +{ + solAssert(m_reservedMemory.has_value(), "Reserved memory was used before."); + size_t reservedMemory = *m_reservedMemory; + m_reservedMemory = std::nullopt; + return reservedMemory; +} + void IRGenerationContext::addStateVariable( VariableDeclaration const& _declaration, u256 _storageOffset, diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 0a07f2f29ffb..a7eab7cebdf2 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -81,6 +81,17 @@ class IRGenerationContext bool isLocalVariable(VariableDeclaration const& _varDecl) const { return m_localVariables.count(&_varDecl); } IRVariable const& localVariable(VariableDeclaration const& _varDecl); + /// Registers an immutable variable of the contract. + /// Should only be called at construction time. + void registerImmutableVariable(VariableDeclaration const& _varDecl); + /// @returns the reserved memory for storing the value of the + /// immutable @a _variable during contract creation. + size_t immutableMemoryOffset(VariableDeclaration const& _variable) const; + /// @returns the reserved memory and resets it to mark it as used. + /// Intended to be used only once for initializing the free memory pointer + /// to after the area used for immutables. + size_t reservedMemory(); + void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset); bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); } std::pair storageLocationOfVariable(VariableDeclaration const& _varDecl) const @@ -123,6 +134,12 @@ class IRGenerationContext OptimiserSettings m_optimiserSettings; ContractDefinition const* m_mostDerivedContract = nullptr; std::map m_localVariables; + /// Memory offsets reserved for the values of immutable variables during contract creation. + /// This map is empty in the runtime context. + std::map m_immutableVariables; + /// Total amount of reserved memory. Reserved memory is used to store + /// immutable variables during contract creation. + std::optional m_reservedMemory = {0}; /// Storage offsets of state variables std::map> m_stateVariables; MultiUseYulFunctionCollector m_functions; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index aed373c1018f..be878e739066 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -38,9 +38,6 @@ #include -#include -#include - #include using namespace std; @@ -114,6 +111,8 @@ string IRGenerator::generate( )"); resetContext(_contract); + for (VariableDeclaration const* var: ContractType(_contract).immutableVariables()) + m_context.registerImmutableVariable(*var); t("CreationObject", m_context.creationObjectName(_contract)); t("memoryInit", memoryInit()); @@ -142,6 +141,7 @@ string IRGenerator::generate( t("subObjects", subObjectSources(m_context.subObjectsCreated())); resetContext(_contract); + // Do not register immutables to avoid assignment. t("RuntimeObject", m_context.runtimeObjectName(_contract)); t("dispatch", dispatchRoutine(_contract)); generateQueuedFunctions(); @@ -169,24 +169,24 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) string functionName = m_context.functionName(_function); return m_context.functionCollector().createFunction(functionName, [&]() { Whiskers t(R"( - function () { + function () -> { } )"); t("functionName", functionName); - string params; + vector params; for (auto const& varDecl: _function.parameters()) - params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); - t("params", params); - string retParams; + params += m_context.addLocalVariable(*varDecl).stackSlots(); + t("params", joinHumanReadable(params)); + vector retParams; string retInit; for (auto const& varDecl: _function.returnParameters()) { - retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); + retParams += m_context.addLocalVariable(*varDecl).stackSlots(); retInit += generateInitialAssignment(*varDecl); } - t("returns", retParams.empty() ? "" : " -> " + retParams); + t("retParams", joinHumanReadable(retParams)); t("initReturnVariables", retInit); t("body", generate(_function.body())); return t.render(); @@ -199,12 +199,11 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) Type const* type = _varDecl.annotation().type; - solAssert(!_varDecl.isConstant(), ""); - solAssert(!_varDecl.immutable(), ""); solAssert(_varDecl.isStateVariable(), ""); if (auto const* mappingType = dynamic_cast(type)) return m_context.functionCollector().createFunction(functionName, [&]() { + solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), ""); pair slot_offset = m_context.storageLocationOfVariable(_varDecl); solAssert(slot_offset.second == 0, ""); FunctionType funType(_varDecl); @@ -254,17 +253,42 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) solUnimplementedAssert(type->isValueType(), ""); return m_context.functionCollector().createFunction(functionName, [&]() { - pair slot_offset = m_context.storageLocationOfVariable(_varDecl); - - return Whiskers(R"( - function () -> rval { - rval := () - } - )") - ("functionName", functionName) - ("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false)) - ("slot", slot_offset.first.str()) - .render(); + if (_varDecl.immutable()) + { + solUnimplementedAssert(type->sizeOnStack() == 1, ""); + return Whiskers(R"( + function () -> rval { + rval := loadimmutable("") + } + )") + ("functionName", functionName) + ("id", to_string(_varDecl.id())) + .render(); + } + else if (_varDecl.isConstant()) + return Whiskers(R"( + function () -> { + := () + } + )") + ("functionName", functionName) + ("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl)) + ("ret", suffixedVariableNameList("ret_", 0, _varDecl.type()->sizeOnStack())) + .render(); + else + { + pair slot_offset = m_context.storageLocationOfVariable(_varDecl); + + return Whiskers(R"( + function () -> rval { + rval := () + } + )") + ("functionName", functionName) + ("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false)) + ("slot", slot_offset.first.str()) + .render(); + } }); } } @@ -276,31 +300,35 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec return generator.code(); } -pair> IRGenerator::evaluateConstructorArguments( +pair>> IRGenerator::evaluateConstructorArguments( ContractDefinition const& _contract ) { - map constructorParams; + map> constructorParams; vector>const *>> baseConstructorArguments; for (ASTPointer const& base: _contract.baseContracts()) if (FunctionDefinition const* baseConstructor = dynamic_cast( - base->name().annotation().referencedDeclaration - )->constructor(); baseConstructor && base->arguments()) + base->name().annotation().referencedDeclaration + )->constructor(); baseConstructor && base->arguments()) baseConstructorArguments.emplace_back( - dynamic_cast(baseConstructor->scope()), - base->arguments() + dynamic_cast(baseConstructor->scope()), + base->arguments() ); if (FunctionDefinition const* constructor = _contract.constructor()) - for (auto const& modifier: constructor->modifiers()) - if (FunctionDefinition const* baseConstructor = dynamic_cast( + for (ASTPointer const& modifier: constructor->modifiers()) + if (auto const* baseContract = dynamic_cast( modifier->name()->annotation().referencedDeclaration - )->constructor(); baseConstructor && modifier->arguments()) - baseConstructorArguments.emplace_back( - dynamic_cast(baseConstructor->scope()), - modifier->arguments() - ); + )) + if ( + FunctionDefinition const* baseConstructor = baseContract->constructor(); + baseConstructor && modifier->arguments() + ) + baseConstructorArguments.emplace_back( + dynamic_cast(baseConstructor->scope()), + modifier->arguments() + ); IRGeneratorForStatements generator{m_context, m_utils}; for (auto&& [baseContract, arguments]: baseConstructorArguments) @@ -310,11 +338,11 @@ pair> IRGenerator::evaluateConstr { vector params; for (size_t i = 0; i < arguments->size(); ++i) - params.emplace_back(generator.evaluateExpression( - *(arguments->at(i)), - *(baseContract->constructor()->parameters()[i]->type()) - ).commaSeparatedList()); - constructorParams[baseContract] = joinHumanReadable(params); + params += generator.evaluateExpression( + *(arguments->at(i)), + *(baseContract->constructor()->parameters()[i]->type()) + ).stackSlots(); + constructorParams[baseContract] = std::move(params); } } @@ -325,7 +353,7 @@ string IRGenerator::initStateVariables(ContractDefinition const& _contract) { IRGeneratorForStatements generator{m_context, m_utils}; for (VariableDeclaration const* variable: _contract.stateVariables()) - if (!variable->isConstant() && !variable->immutable()) + if (!variable->isConstant()) generator.initializeStateVar(*variable); return generator.code(); @@ -335,16 +363,16 @@ string IRGenerator::initStateVariables(ContractDefinition const& _contract) void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract) { auto listAllParams = [&]( - map const& baseParams) -> string + map> const& baseParams) -> vector { vector params; for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) if (baseParams.count(contract)) - params.emplace_back(baseParams.at(contract)); - return joinHumanReadable(params); + params += baseParams.at(contract); + return params; }; - map baseConstructorParams; + map> baseConstructorParams; for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i) { ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i]; @@ -359,16 +387,16 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra } )"); - string params; + vector params; if (contract->constructor()) for (ASTPointer const& varDecl: contract->constructor()->parameters()) - params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); - t("params", params); - string baseParamsString = listAllParams(baseConstructorParams); - t("baseParams", baseParamsString); - t("comma", !params.empty() && !baseParamsString.empty() ? ", " : ""); + params += m_context.addLocalVariable(*varDecl).stackSlots(); + t("params", joinHumanReadable(params)); + vector baseParams = listAllParams(baseConstructorParams); + t("baseParams", joinHumanReadable(baseParams)); + t("comma", !params.empty() && !baseParams.empty() ? ", " : ""); t("functionName", implicitConstructorName(*contract)); - pair> evaluatedArgs = evaluateConstructorArguments(*contract); + pair>> evaluatedArgs = evaluateConstructorArguments(*contract); baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end()); t("evalBaseArguments", evaluatedArgs.first); if (i < _contract.annotation().linearizedBaseContracts.size() - 1) @@ -376,7 +404,7 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra t("hasNextConstructor", true); ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1]; t("nextConstructor", implicitConstructorName(*nextContract)); - t("nextParams", listAllParams(baseConstructorParams)); + t("nextParams", joinHumanReadable(listAllParams(baseConstructorParams))); } else t("hasNextConstructor", false); @@ -391,10 +419,41 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra string IRGenerator::deployCode(ContractDefinition const& _contract) { Whiskers t(R"X( + <#loadImmutables> + let := mload() + + codecopy(0, dataoffset(""), datasize("")) + + <#storeImmutables> + setimmutable("", ) + + return(0, datasize("")) )X"); t("object", m_context.runtimeObjectName(_contract)); + + vector> loadImmutables; + vector> storeImmutables; + + for (VariableDeclaration const* immutable: ContractType(_contract).immutableVariables()) + { + solUnimplementedAssert(immutable->type()->isValueType(), ""); + solUnimplementedAssert(immutable->type()->sizeOnStack() == 1, ""); + string yulVar = m_context.newYulVariable(); + loadImmutables.emplace_back(map{ + {"var"s, yulVar}, + {"memoryOffset"s, to_string(m_context.immutableMemoryOffset(*immutable))} + }); + storeImmutables.emplace_back(map{ + {"var"s, yulVar}, + {"immutableName"s, to_string(immutable->id())} + }); + } + t("loadImmutables", std::move(loadImmutables)); + // reverse order to ease stack strain + reverse(storeImmutables.begin(), storeImmutables.end()); + t("storeImmutables", std::move(storeImmutables)); return t.render(); } @@ -420,10 +479,10 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) { // - (4, calldatasize()) - () + let := (4, calldatasize()) + let := () let memPos := (0) - let memEnd := (memPos ) + let memEnd := (memPos , ) return(memPos, sub(memEnd, memPos)) } @@ -445,13 +504,11 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) unsigned paramVars = make_shared(type->parameterTypes())->sizeOnStack(); unsigned retVars = make_shared(type->returnParameterTypes())->sizeOnStack(); - templ["assignToParams"] = paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := "; - templ["assignToRetParams"] = retVars == 0 ? "" : "let " + suffixedVariableNameList("ret_", 0, retVars) + " := "; ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes()); templ["params"] = suffixedVariableNameList("param_", 0, paramVars); - templ["retParams"] = suffixedVariableNameList("ret_", retVars, 0); + templ["retParams"] = suffixedVariableNameList("ret_", 0, retVars); if (FunctionDefinition const* funDef = dynamic_cast(&type->declaration())) templ["function"] = m_context.enqueueFunctionForCodeGeneration(*funDef); @@ -462,7 +519,6 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) templ["allocate"] = m_utils.allocationFunction(); templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false); - templ["comma"] = retVars == 0 ? "" : ", "; } t("cases", functions); if (FunctionDefinition const* fallback = _contract.fallbackFunction()) @@ -489,9 +545,9 @@ string IRGenerator::memoryInit() // and thus can assume all memory to be zero, including the contents of // the "zero memory area" (the position CompilerUtils::zeroPointer points to). return - Whiskers{"mstore(, )"} + Whiskers{"mstore(, )"} ("memPtr", to_string(CompilerUtils::freeMemoryPointer)) - ("generalPurposeStart", to_string(CompilerUtils::generalPurposeMemoryStart)) + ("freeMemoryStart", to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory())) .render(); } diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index a4298a902b47..642cfcdfbe27 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -81,9 +81,8 @@ class IRGenerator /// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of /// @a _contract /// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params - std::pair> evaluateConstructorArguments( - ContractDefinition const& _contract - ); + std::pair>> + evaluateConstructorArguments(ContractDefinition const& _contract); /// Initializes state variables of /// @a _contract diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 755110c27b0a..553f618cd8cb 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -42,7 +42,6 @@ #include #include -#include #include using namespace std; @@ -117,10 +116,12 @@ struct CopyTranslate: public yul::ASTCopier reference.isOffset == false && reference.isSlot == false, "Should not be called for offset/slot" ); + auto const& var = m_context.localVariable(*varDecl); + solAssert(var.type().sizeOnStack() == 1, ""); return yul::Identifier{ _identifier.location, - yul::YulString{m_context.localVariable(*varDecl).name()} + yul::YulString{var.commaSeparatedList()} }; } @@ -140,20 +141,21 @@ string IRGeneratorForStatements::code() const void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _varDecl) { - solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable."); + solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable."); solAssert(!_varDecl.isConstant(), ""); - solAssert(!_varDecl.immutable(), ""); - if (_varDecl.value()) - { - _varDecl.value()->accept(*this); - writeToLValue(IRLValue{ - *_varDecl.annotation().type, - IRLValue::Storage{ - util::toCompactHexWithPrefix(m_context.storageLocationOfVariable(_varDecl).first), - m_context.storageLocationOfVariable(_varDecl).second - } - }, *_varDecl.value()); - } + if (!_varDecl.value()) + return; + + _varDecl.value()->accept(*this); + writeToLValue( + _varDecl.immutable() ? + IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} : + IRLValue{*_varDecl.annotation().type, IRLValue::Storage{ + util::toCompactHexWithPrefix(m_context.storageLocationOfVariable(_varDecl).first), + m_context.storageLocationOfVariable(_varDecl).second + }}, + *_varDecl.value() + ); } void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl) @@ -177,6 +179,28 @@ IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expre return variable; } +string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant) +{ + string functionName = "constant_" + _constant.name() + "_" + to_string(_constant.id()); + return m_context.functionCollector().createFunction(functionName, [&] { + Whiskers templ(R"( + function () -> { + + := + } + )"); + templ("functionName", functionName); + IRGeneratorForStatements generator(m_context, m_utils); + solAssert(_constant.value(), ""); + Type const& constantType = *_constant.type(); + templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList()); + templ("code", generator.code()); + templ("ret", IRVariable("ret", constantType).commaSeparatedList()); + + return templ.render(); + }); +} + void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement) { if (Expression const* expression = _varDeclStatement.initialValue()) @@ -229,29 +253,53 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional) bool IRGeneratorForStatements::visit(Assignment const& _assignment) { _assignment.rightHandSide().accept(*this); - Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType( - &type(_assignment.leftHandSide()) - ); - IRVariable value = convert(_assignment.rightHandSide(), *intermediateType); + Token assignmentOperator = _assignment.assignmentOperator(); + Token binaryOperator = + assignmentOperator == Token::Assign ? + assignmentOperator : + TokenTraits::AssignmentToBinaryOp(assignmentOperator); + + Type const* rightIntermediateType = + TokenTraits::isShiftOp(binaryOperator) ? + type(_assignment.rightHandSide()).mobileType() : + type(_assignment.rightHandSide()).closestTemporaryType( + &type(_assignment.leftHandSide()) + ); + solAssert(rightIntermediateType, ""); + IRVariable value = convert(_assignment.rightHandSide(), *rightIntermediateType); _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - if (_assignment.assignmentOperator() != Token::Assign) + if (assignmentOperator != Token::Assign) { - solAssert(type(_assignment.leftHandSide()) == *intermediateType, ""); - solAssert(intermediateType->isValueType(), "Compound operators only available for value types."); - + solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types."); + solAssert(rightIntermediateType->isValueType(), "Compound operators only available for value types."); IRVariable leftIntermediate = readFromLValue(*m_currentLValue); - m_code << value.name() << " := " << binaryOperation( - TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()), - *intermediateType, - leftIntermediate.name(), - value.name() - ); + if (TokenTraits::isShiftOp(binaryOperator)) + { + solAssert(type(_assignment) == leftIntermediate.type(), ""); + solAssert(type(_assignment) == type(_assignment.leftHandSide()), ""); + define(_assignment) << shiftOperation(binaryOperator, leftIntermediate, value); + + writeToLValue(*m_currentLValue, IRVariable(_assignment)); + m_currentLValue.reset(); + return false; + } + else + { + solAssert(type(_assignment.leftHandSide()) == *rightIntermediateType, ""); + m_code << value.name() << " := " << binaryOperation( + binaryOperator, + *rightIntermediateType, + leftIntermediate.name(), + value.name() + ); + } } writeToLValue(*m_currentLValue, value); + m_currentLValue.reset(); if (*_assignment.annotation().type != *TypeProvider::emptyTuple()) define(_assignment, value); @@ -476,12 +524,16 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) return false; } + if (commonType->category() == Type::Category::RationalNumber) + { + define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n"; + return false; // skip sub-expressions + } + _binOp.leftExpression().accept(*this); _binOp.rightExpression().accept(*this); - if (commonType->category() == Type::Category::RationalNumber) - define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n"; - else if (TokenTraits::isCompareOp(op)) + if (TokenTraits::isCompareOp(op)) { if (auto type = dynamic_cast(commonType)) { @@ -495,9 +547,9 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) isSigned = type->isSigned(); string args = - expressionAsType(_binOp.leftExpression(), *commonType) + + expressionAsType(_binOp.leftExpression(), *commonType, true) + ", " + - expressionAsType(_binOp.rightExpression(), *commonType); + expressionAsType(_binOp.rightExpression(), *commonType, true); string expr; if (op == Token::Equal) @@ -516,6 +568,12 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) solAssert(false, "Unknown comparison operator."); define(_binOp) << expr << "\n"; } + else if (TokenTraits::isShiftOp(op)) + { + IRVariable left = convert(_binOp.leftExpression(), *commonType); + IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType()); + define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n"; + } else { string left = expressionAsType(_binOp.leftExpression(), *commonType); @@ -583,13 +641,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) break; case FunctionType::Kind::Internal: { - vector args; - for (unsigned i = 0; i < arguments.size(); ++i) - if (functionType->takesArbitraryParameters()) - args.emplace_back(IRVariable(*arguments[i]).commaSeparatedList()); - else - args.emplace_back(convert(*arguments[i], *parameterTypes[i]).commaSeparatedList()); - optional functionDef; if (auto memberAccess = dynamic_cast(&_functionCall.expression())) { @@ -627,6 +678,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) solAssert(functionDef.has_value(), ""); solAssert(functionDef.value() == nullptr || functionDef.value()->isImplemented(), ""); + vector args; + for (size_t i = 0; i < arguments.size(); ++i) + if (functionType->takesArbitraryParameters()) + args += IRVariable(*arguments[i]).stackSlots(); + else + args += convert(*arguments[i], *parameterTypes[i]).stackSlots(); + if (functionDef.value() != nullptr) define(_functionCall) << m_context.enqueueFunctionForCodeGeneration(*functionDef.value()) << @@ -648,10 +706,12 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } case FunctionType::Kind::External: case FunctionType::Kind::DelegateCall: + appendExternalFunctionCall(_functionCall, arguments); + break; case FunctionType::Kind::BareCall: case FunctionType::Kind::BareDelegateCall: case FunctionType::Kind::BareStaticCall: - appendExternalFunctionCall(_functionCall, arguments); + appendBareCall(_functionCall, arguments); break; case FunctionType::Kind::BareCallCode: solAssert(false, "Callcode has been removed."); @@ -662,7 +722,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); vector indexedArgs; - string nonIndexedArgs; + vector nonIndexedArgs; TypePointers nonIndexedArgTypes; TypePointers nonIndexedParamTypes; if (!event.isAnonymous()) @@ -685,10 +745,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } else { - string vars = IRVariable(arg).commaSeparatedList(); - if (!vars.empty()) - // In reverse because abi_encode expects it like that. - nonIndexedArgs = ", " + move(vars) + nonIndexedArgs; + nonIndexedArgs += IRVariable(arg).stackSlots(); nonIndexedArgTypes.push_back(arg.annotation().type); nonIndexedParamTypes.push_back(paramTypes[i]); } @@ -703,7 +760,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) templ("end", m_context.newYulVariable()); templ("freeMemory", freeMemory()); templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes)); - templ("nonIndexedArgs", nonIndexedArgs); + templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs)); templ("log", "log" + to_string(indexedArgs.size())); templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | boost::adaptors::transformed([&](auto const& _arg) { return _arg.commaSeparatedList(); @@ -730,13 +787,134 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) break; } + case FunctionType::Kind::ABIEncode: + case FunctionType::Kind::ABIEncodePacked: + case FunctionType::Kind::ABIEncodeWithSelector: + case FunctionType::Kind::ABIEncodeWithSignature: + { + bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked; + solAssert(functionType->padArguments() != isPacked, ""); + bool const hasSelectorOrSignature = + functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector || + functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature; + + TypePointers argumentTypes; + TypePointers targetTypes; + vector argumentVars; + for (size_t i = 0; i < arguments.size(); ++i) + { + // ignore selector + if (hasSelectorOrSignature && i == 0) + continue; + argumentTypes.emplace_back(&type(*arguments[i])); + targetTypes.emplace_back(type(*arguments[i]).fullEncodingType(false, true, isPacked)); + argumentVars += IRVariable(*arguments[i]).stackSlots(); + } + + string selector; + if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature) + { + // hash the signature + Type const& selectorType = type(*arguments.front()); + if (auto const* stringType = dynamic_cast(&selectorType)) + { + FixedHash<4> hash(keccak256(stringType->value())); + selector = formatNumber(u256(FixedHash<4>::Arith(hash)) << (256 - 32)); + } + else + { + // Used to reset the free memory pointer later. + string freeMemoryPre = m_context.newYulVariable(); + m_code << "let " << freeMemoryPre << " := " << freeMemory() << "\n"; + IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory()); + IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32)); + + define(hashVariable) << + "keccak256(" << + m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory()) << + "(" << + array.commaSeparatedList() << + "), " << + m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()) << + "(" << + array.commaSeparatedList() << + "))\n"; + IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4)); + define(selectorVariable, hashVariable); + m_code << "mstore(" << to_string(CompilerUtils::freeMemoryPointer) << ", " << freeMemoryPre << ")\n"; + } + } + else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector) + selector = convert(*arguments.front(), *TypeProvider::fixedBytes(4)).name(); + + Whiskers templ(R"( + let := () + let := add(, 0x20) + + mstore(, ) + := add(, 4) + + let := () + mstore(, sub(, add(, 0x20))) + mstore(, ()) + )"); + templ("data", IRVariable(_functionCall).part("mpos").name()); + templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); + templ("mpos", m_context.newYulVariable()); + templ("mend", m_context.newYulVariable()); + templ("selector", selector); + templ("encode", + isPacked ? + m_context.abiFunctions().tupleEncoderPacked(argumentTypes, targetTypes) : + m_context.abiFunctions().tupleEncoder(argumentTypes, targetTypes, false) + ); + templ("arguments", joinHumanReadablePrefixed(argumentVars)); + templ("freeMemPtr", to_string(CompilerUtils::freeMemoryPointer)); + templ("roundUp", m_utils.roundUpFunction()); + + m_code << templ.render(); + break; + } case FunctionType::Kind::Revert: { solAssert(arguments.size() == parameterTypes.size(), ""); if (arguments.empty()) m_code << "revert(0, 0)\n"; else - solUnimplementedAssert(false, ""); + { + solAssert(arguments.size() == 1, ""); + + if (m_context.revertStrings() == RevertStrings::Strip) + m_code << "revert(0, 0)\n"; + else + { + solAssert(type(*arguments.front()).isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),""); + + Whiskers templ(R"({ + let := () + mstore(, ) + let := (add(, 4) ) + revert(, sub(, )) + })"); + templ("pos", m_context.newYulVariable()); + templ("end", m_context.newYulVariable()); + templ( + "hash", + (u256(util::FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256("Error(string)")))) << (256 - 32)).str() + ); + templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); + templ( + "argumentVars", + joinHumanReadablePrefixed(IRVariable{*arguments.front()}.stackSlots()) + ); + templ("encode", m_context.abiFunctions().tupleEncoder( + {&type(*arguments.front())}, + {TypeProvider::stringMemory()} + )); + + m_code << templ.render(); + } + } break; } @@ -759,6 +937,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) solAssert(arguments.size() == 1, ""); ArrayType const* arrayType = TypeProvider::bytesMemory(); + auto array = convert(*arguments[0], *arrayType); define(_functionCall) << @@ -828,15 +1007,43 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { break; } - case FunctionType::Kind::GasLeft: + case FunctionType::Kind::AddMod: + case FunctionType::Kind::MulMod: { - define(_functionCall) << "gas()\n"; + static map functions = { + {FunctionType::Kind::AddMod, "addmod"}, + {FunctionType::Kind::MulMod, "mulmod"}, + }; + solAssert(functions.find(functionType->kind()) != functions.end(), ""); + solAssert(arguments.size() == 3 && parameterTypes.size() == 3, ""); + + IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2])); + define(modulus, *arguments[2]); + Whiskers templ("if iszero() { invalid() }\n"); + m_code << templ("modulus", modulus.name()).render(); + + string args; + for (size_t i = 0; i < 2; ++i) + args += expressionAsType(*arguments[i], *(parameterTypes[i])) + ", "; + args += modulus.name(); + define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n"; break; } + case FunctionType::Kind::GasLeft: case FunctionType::Kind::Selfdestruct: + case FunctionType::Kind::BlockHash: { - solAssert(arguments.size() == 1, ""); - define(_functionCall) << "selfdestruct(" << expressionAsType(*arguments.front(), *parameterTypes.front()) << ")\n"; + static map functions = { + {FunctionType::Kind::GasLeft, "gas"}, + {FunctionType::Kind::Selfdestruct, "selfdestruct"}, + {FunctionType::Kind::BlockHash, "blockhash"}, + }; + solAssert(functions.find(functionType->kind()) != functions.end(), ""); + + string args; + for (size_t i = 0; i < arguments.size(); ++i) + args += (args.empty() ? "" : ", ") + expressionAsType(*arguments[i], *(parameterTypes[i])); + define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n"; break; } case FunctionType::Kind::Log0: @@ -876,11 +1083,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) ); TypePointers argumentTypes; - string constructorParams; + vector constructorParams; for (ASTPointer const& arg: arguments) { argumentTypes.push_back(arg->annotation().type); - constructorParams += ", " + IRVariable{*arg}.commaSeparatedList(); + constructorParams += IRVariable{*arg}.stackSlots(); } ContractDefinition const* contract = @@ -906,9 +1113,9 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction()); t("object", m_context.creationObjectName(*contract)); t("abiEncode", - m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(),false) + m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) ); - t("constructorParams", constructorParams); + t("constructorParams", joinHumanReadablePrefixed(constructorParams)); t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); t("saltSet", functionType->saltSet()); if (functionType->saltSet()) @@ -1097,7 +1304,20 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) solAssert(false, "Blockhash has been removed."); else if (member == "creationCode" || member == "runtimeCode") { - solUnimplementedAssert(false, ""); + solUnimplementedAssert(member != "runtimeCode", ""); + TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); + ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); + m_context.subObjectsCreated().insert(&contract); + m_code << Whiskers(R"( + let := datasize("") + let := (add(, 32)) + mstore(, ) + datacopy(add(, 32), dataoffset(""), ) + )") + ("allocationFunction", m_utils.allocationFunction()) + ("size", m_context.newYulVariable()) + ("objectName", m_context.creationObjectName(contract)) + ("result", IRVariable(_memberAccess).commaSeparatedList()).render(); } else if (member == "name") { @@ -1112,6 +1332,16 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) result ^= fromBigEndian(function.first.ref()); define(_memberAccess) << formatNumber(u256{result} << (256 - 32)) << "\n"; } + else if (member == "min" || member == "max") + { + MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); + IntegerType const* integerType = dynamic_cast(arg->typeArgument()); + + if (member == "min") + define(_memberAccess) << formatNumber(integerType->min()) << "\n"; + else + define(_memberAccess) << formatNumber(integerType->max()) << "\n"; + } else if (set{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}.count(member)) { // no-op @@ -1283,14 +1513,11 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) solAssert(keyType.sizeOnStack() <= 1, ""); string slot = m_context.newYulVariable(); - Whiskers templ("let := ( )\n"); + Whiskers templ("let := (,)\n"); templ("slot", slot); templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType)); templ("base", IRVariable(_indexAccess.baseExpression()).commaSeparatedList()); - if (keyType.sizeOnStack() == 0) - templ("key", ""); - else - templ("key", ", " + IRVariable(*_indexAccess.indexExpression()).commaSeparatedList()); + templ("key", IRVariable(*_indexAccess.indexExpression()).commaSeparatedList()); m_code << templ.render(); setLValue(_indexAccess, IRLValue{ *_indexAccess.annotation().type, @@ -1513,12 +1740,14 @@ void IRGeneratorForStatements::handleVariableReference( Expression const& _referencingExpression ) { - // TODO for the constant case, we have to be careful: - // If the value is visited twice, `defineExpression` is called twice on - // the same expression. - solUnimplementedAssert(!_variable.isConstant(), ""); - solUnimplementedAssert(!_variable.immutable(), ""); - if (m_context.isLocalVariable(_variable)) + if (_variable.isStateVariable() && _variable.isConstant()) + define(_referencingExpression) << constantValueFunction(_variable) << "()\n"; + else if (_variable.isStateVariable() && _variable.immutable()) + setLValue(_referencingExpression, IRLValue{ + *_variable.annotation().type, + IRLValue::Immutable{&_variable} + }); + else if (m_context.isLocalVariable(_variable)) setLValue(_referencingExpression, IRLValue{ *_variable.annotation().type, IRLValue::Stack{m_context.localVariable(_variable)} @@ -1541,18 +1770,20 @@ void IRGeneratorForStatements::appendExternalFunctionCall( ) { FunctionType const& funType = dynamic_cast(type(_functionCall.expression())); + solAssert(!funType.takesArbitraryParameters(), ""); + solAssert(_arguments.size() == funType.parameterTypes().size(), ""); + solAssert(!funType.isBareCall(), ""); + FunctionType::Kind const funKind = funType.kind(); + solAssert( - funType.takesArbitraryParameters() || - _arguments.size() == funType.parameterTypes().size(), "" + funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall, + "Can only be used for regular external calls." ); - solUnimplementedAssert(!funType.bound(), ""); - FunctionType::Kind const funKind = funType.kind(); - solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); - solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); + solUnimplementedAssert(!funType.bound(), ""); - bool const isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; - bool const useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); + bool const isDelegateCall = funKind == FunctionType::Kind::DelegateCall; + bool const useStaticCall = funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall(); ReturnInfo const returnInfo{m_context.evmVersion(), funType}; @@ -1561,12 +1792,9 @@ void IRGeneratorForStatements::appendExternalFunctionCall( for (auto const& arg: _arguments) { argumentTypes.emplace_back(&type(*arg)); - if (IRVariable(*arg).type().sizeOnStack() > 0) - argumentStrings.emplace_back(IRVariable(*arg).commaSeparatedList()); + argumentStrings += IRVariable(*arg).stackSlots(); } - string argumentString = argumentStrings.empty() ? ""s : (", " + joinHumanReadable(argumentStrings)); - solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); if (!m_context.evmVersion().canOverchargeGasForCall()) { @@ -1578,33 +1806,19 @@ void IRGeneratorForStatements::appendExternalFunctionCall( m_code << "mstore(add(" << freeMemory() << ", " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n"; } - ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); - Whiskers templ(R"( - - if iszero(extcodesize(
)) { revert(0, 0) } - + if iszero(extcodesize(
)) { revert(0, 0) } // storage for arguments and returned data let := - - - mstore(, ()) - - let := ( - - - - add(, 4) - - - ) + mstore(, ()) + let := (add(, 4) ) let := (,
, , , sub(, ), , ) if iszero() { () } - let + let if { // copy dynamic return data out @@ -1615,12 +1829,11 @@ void IRGeneratorForStatements::appendExternalFunctionCall( mstore(, add(, ())) // decode return parameters from external try-call into retVars - := (, add(, )) + := (, add(, )) } )"); templ("pos", m_context.newYulVariable()); templ("end", m_context.newYulVariable()); - templ("bareCall", funType.isBareCall()); if (_functionCall.annotation().tryCall) templ("success", m_context.trySuccessConditionVariable(_functionCall)); else @@ -1628,17 +1841,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall( templ("freeMemory", freeMemory()); templ("shl28", m_utils.shiftLeftFunction(8 * (32 - 4))); - if (!funType.isBareCall()) - templ("funId", IRVariable(_functionCall.expression()).part("functionIdentifier").name()); - - if (funKind == FunctionType::Kind::ECRecover) - templ("address", "1"); - else if (funKind == FunctionType::Kind::SHA256) - templ("address", "2"); - else if (funKind == FunctionType::Kind::RIPEMD160) - templ("address", "3"); - else - templ("address", IRVariable(_functionCall.expression()).part("address").name()); + templ("funId", IRVariable(_functionCall.expression()).part("functionIdentifier").name()); + templ("address", IRVariable(_functionCall.expression()).part("address").name()); // Always use the actual return length, and not our calculated expected length, if returndatacopy is supported. // This ensures it can catch badly formatted input from external calls. @@ -1651,39 +1855,20 @@ void IRGeneratorForStatements::appendExternalFunctionCall( string const retVars = IRVariable(_functionCall).commaSeparatedList(); templ("retVars", retVars); - templ("hasRetVars", !retVars.empty()); solAssert(retVars.empty() == returnInfo.returnTypes.empty(), ""); templ("roundUp", m_utils.roundUpFunction()); - templ("abiDecode", abi.tupleDecoder(returnInfo.returnTypes, true)); + templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true)); templ("dynamicReturnSize", returnInfo.dynamicReturnSize); templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)); templ("noTryCall", !_functionCall.annotation().tryCall); - // If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place. - // Move arguments to memory, will not update the free memory pointer (but will update the memory - // pointer on the stack). - bool encodeInPlace = funType.takesArbitraryParameters() || funType.isBareCall(); - if (funType.kind() == FunctionType::Kind::ECRecover) - // This would be the only combination of padding and in-place encoding, - // but all parameters of ecrecover are value types anyway. - encodeInPlace = false; bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall; - solUnimplementedAssert(encodeInPlace == !funType.padArguments(), ""); - if (encodeInPlace) - { - solUnimplementedAssert(!encodeForLibraryCall, ""); - templ("encodeArgs", abi.tupleEncoderPacked(argumentTypes, funType.parameterTypes())); - } - else - templ("encodeArgs", abi.tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall)); - templ("argumentString", argumentString); - - // Output data will replace input data, unless we have ECRecover (then, output - // area will be 32 bytes just before input area). - solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); + solAssert(funType.padArguments(), ""); + templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall)); + templ("argumentString", joinHumanReadablePrefixed(argumentStrings)); solAssert(!isDelegateCall || !funType.valueSet(), "Value set for delegatecall"); solAssert(!useStaticCall || !funType.valueSet(), "Value set for staticcall"); @@ -1691,10 +1876,6 @@ void IRGeneratorForStatements::appendExternalFunctionCall( templ("hasValue", !isDelegateCall && !useStaticCall); templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); - // Check that the target contract exists (has code) for non-low-level calls. - bool checkExistence = (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall); - templ("checkExistence", checkExistence); - if (funType.gasSet()) templ("gas", IRVariable(_functionCall.expression()).part("gas").name()); else if (m_context.evmVersion().canOverchargeGasForCall()) @@ -1707,8 +1888,6 @@ void IRGeneratorForStatements::appendExternalFunctionCall( u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10; if (funType.valueSet()) gasNeededByCaller += evmasm::GasCosts::callValueTransferGas; - if (!checkExistence) - gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")"); } // Order is important here, STATICCALL might overlap with DELEGATECALL. @@ -1721,8 +1900,103 @@ void IRGeneratorForStatements::appendExternalFunctionCall( templ("forwardingRevert", m_utils.forwardingRevertFunction()); - solUnimplementedAssert(funKind != FunctionType::Kind::RIPEMD160, ""); - solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); + m_code << templ.render(); +} + +void IRGeneratorForStatements::appendBareCall( + FunctionCall const& _functionCall, + vector> const& _arguments +) +{ + FunctionType const& funType = dynamic_cast(type(_functionCall.expression())); + solAssert( + !funType.bound() && + !funType.takesArbitraryParameters() && + _arguments.size() == 1 && + funType.parameterTypes().size() == 1, "" + ); + FunctionType::Kind const funKind = funType.kind(); + + solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); + solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); + solAssert( + funKind == FunctionType::Kind::BareCall || + funKind == FunctionType::Kind::BareDelegateCall || + funKind == FunctionType::Kind::BareStaticCall, "" + ); + + solAssert(!_functionCall.annotation().tryCall, ""); + Whiskers templ(R"( + + let := mload() + let := sub(( , ), ) + + let := add(, 0x20) + let := mload() + + + let := (,
, , , , 0, 0) + + let := () + + )"); + + templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)); + templ("pos", m_context.newYulVariable()); + templ("length", m_context.newYulVariable()); + + templ("arg", IRVariable(*_arguments.front()).commaSeparatedList()); + Type const& argType = type(*_arguments.front()); + if (argType == *TypeProvider::bytesMemory() || argType == *TypeProvider::stringMemory()) + templ("needsEncoding", false); + else + { + templ("needsEncoding", true); + ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); + templ("encode", abi.tupleEncoderPacked({&argType}, {TypeProvider::bytesMemory()})); + } + + templ("success", IRVariable(_functionCall).tupleComponent(0).name()); + if (IRVariable(_functionCall).tupleComponent(1).type().category() == Type::Category::InaccessibleDynamic) + templ("returndataVar", ""); + else + { + templ("returndataVar", IRVariable(_functionCall).tupleComponent(1).part("mpos").name()); + templ("extractReturndataFunction", m_utils.extractReturndataFunction()); + } + + templ("address", IRVariable(_functionCall.expression()).part("address").name()); + + if (funKind == FunctionType::Kind::BareCall) + { + templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); + templ("call", "call"); + } + else + { + solAssert(!funType.valueSet(), "Value set for delegatecall or staticcall."); + templ("value", ""); + if (funKind == FunctionType::Kind::BareStaticCall) + templ("call", "staticcall"); + else + templ("call", "delegatecall"); + } + + if (funType.gasSet()) + templ("gas", IRVariable(_functionCall.expression()).part("gas").name()); + else if (m_context.evmVersion().canOverchargeGasForCall()) + // Send all gas (requires tangerine whistle EVM) + templ("gas", "gas()"); + else + { + // send all gas except the amount needed to execute "SUB" and "CALL" + // @todo this retains too much gas for now, needs to be fine-tuned. + u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10; + if (funType.valueSet()) + gasNeededByCaller += evmasm::GasCosts::callValueTransferGas; + gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know + templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")"); + } m_code << templ.render(); } @@ -1744,11 +2018,16 @@ IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const } } -std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to) +std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup) { IRVariable from(_expression); if (from.type() == _to) - return from.commaSeparatedList(); + { + if (_forceCleanup) + return m_utils.cleanupFunction(_to) + "(" + from.commaSeparatedList() + ")"; + else + return from.commaSeparatedList(); + } else return m_utils.conversionFunction(from.type(), _to) + "(" + from.commaSeparatedList() + ")"; } @@ -1827,6 +2106,10 @@ string IRGeneratorForStatements::binaryOperation( string const& _right ) { + solAssert( + !TokenTraits::isShiftOp(_operator), + "Have to use specific shift operation function for shifts." + ); if (IntegerType const* type = dynamic_cast(&_type)) { string fun; @@ -1870,6 +2153,31 @@ string IRGeneratorForStatements::binaryOperation( return {}; } +std::string IRGeneratorForStatements::shiftOperation( + langutil::Token _operator, + IRVariable const& _value, + IRVariable const& _amountToShift +) +{ + IntegerType const* amountType = dynamic_cast(&_amountToShift.type()); + solAssert(amountType, ""); + + solAssert(_operator == Token::SHL || _operator == Token::SAR, ""); + + return + Whiskers(R"( + (, ) + )") + ("shift", + _operator == Token::SHL ? + m_utils.typedShiftLeftFunction(_value.type(), *amountType) : + m_utils.typedShiftRightFunction(_value.type(), *amountType) + ) + ("value", _value.name()) + ("amount", _amountToShift.name()) + .render(); +} + void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp) { langutil::Token const op = _binOp.getOperator(); @@ -1939,6 +2247,18 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable } }, [&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); }, + [&](IRLValue::Immutable const& _immutable) + { + solUnimplementedAssert(_lvalue.type.isValueType(), ""); + solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); + solAssert(_lvalue.type == *_immutable.variable->type(), ""); + size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable); + + IRVariable prepared(m_context.newYulVariable(), _lvalue.type); + define(prepared, _value); + + m_code << "mstore(" << to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n"; + }, [&](IRLValue::Tuple const& _tuple) { auto components = std::move(_tuple.components); for (size_t i = 0; i < components.size(); i++) @@ -1976,13 +2296,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) ")\n"; }, [&](IRLValue::Memory const& _memory) { - if (_memory.byteArrayElement) - define(result) << - m_utils.cleanupFunction(_lvalue.type) << - "(mload(" << - _memory.address << - "))\n"; - else if (_lvalue.type.isValueType()) + if (_lvalue.type.isValueType()) define(result) << m_utils.readFromMemory(_lvalue.type) << "(" << @@ -1994,6 +2308,12 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) [&](IRLValue::Stack const& _stack) { define(result, _stack.variable); }, + [&](IRLValue::Immutable const& _immutable) { + solUnimplementedAssert(_lvalue.type.isValueType(), ""); + solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); + solAssert(_lvalue.type == *_immutable.variable->type(), ""); + define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n"; + }, [&](IRLValue::Tuple const&) { solAssert(false, "Attempted to read from tuple lvalue."); } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index b8fafd8b663a..42d355ddd547 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -54,6 +54,10 @@ class IRGeneratorForStatements: public ASTConstVisitor /// Calculates expression's value and returns variable where it was stored IRVariable evaluateExpression(Expression const& _expression, Type const& _to); + /// @returns the name of a function that computes the value of the given constant + /// and also generates the function. + std::string constantValueFunction(VariableDeclaration const& _constant); + void endVisit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Conditional const& _conditional) override; bool visit(Assignment const& _assignment) override; @@ -102,6 +106,13 @@ class IRGeneratorForStatements: public ASTConstVisitor std::vector> const& _arguments ); + /// Appends code for .call / .delegatecall / .staticcall. + /// All involved expressions have already been visited. + void appendBareCall( + FunctionCall const& _functionCall, + std::vector> const& _arguments + ); + /// @returns code that evaluates to the first unused memory slot (which does not have to /// be empty). static std::string freeMemory(); @@ -112,7 +123,8 @@ class IRGeneratorForStatements: public ASTConstVisitor /// @returns a Yul expression representing the current value of @a _expression, /// converted to type @a _to if it does not yet have that type. - std::string expressionAsType(Expression const& _expression, Type const& _to); + /// If @a _forceCleanup is set to true, it also cleans the value, in case it already has type @a _to. + std::string expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup = false); /// @returns an output stream that can be used to define @a _var using a function call or /// single stack slot expression. @@ -142,6 +154,11 @@ class IRGeneratorForStatements: public ASTConstVisitor std::string const& _right ); + /// @returns code to perform the given shift operation. + /// The operation itself will be performed in the type of the value, + /// while the amount to shift can have its own type. + std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount); + /// Assigns the value of @a _value to the lvalue @a _lvalue. void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value); /// @returns a fresh IR variable containing the value of the lvalue @a _lvalue. diff --git a/libsolidity/codegen/ir/IRLValue.h b/libsolidity/codegen/ir/IRLValue.h index 02d46b6e4146..c5eadc9b2753 100644 --- a/libsolidity/codegen/ir/IRLValue.h +++ b/libsolidity/codegen/ir/IRLValue.h @@ -35,6 +35,10 @@ struct IRLValue { IRVariable variable; }; + struct Immutable + { + VariableDeclaration const* variable = nullptr; + }; struct Storage { std::string const slot; @@ -59,7 +63,7 @@ struct IRLValue { std::vector> components; }; - std::variant kind; + std::variant kind; }; -} \ No newline at end of file +} diff --git a/libsolidity/codegen/ir/IRVariable.cpp b/libsolidity/codegen/ir/IRVariable.cpp index dac1087f0080..1c5ed42bf805 100644 --- a/libsolidity/codegen/ir/IRVariable.cpp +++ b/libsolidity/codegen/ir/IRVariable.cpp @@ -54,7 +54,7 @@ IRVariable IRVariable::part(string const& _name) const solAssert(itemName.empty() || itemType, ""); return IRVariable{suffixedName(itemName), itemType ? *itemType : m_type}; } - solAssert(false, "Invalid stack item name."); + solAssert(false, "Invalid stack item name: " + _name); } vector IRVariable::stackSlots() const @@ -89,7 +89,7 @@ string IRVariable::name() const { solAssert(m_type.sizeOnStack() == 1, ""); auto const& [itemName, type] = m_type.stackItems().front(); - solAssert(!type, ""); + solAssert(!type, "Expected null type for name " + itemName); return suffixedName(itemName); } diff --git a/libsolidity/codegen/ir/IRVariable.h b/libsolidity/codegen/ir/IRVariable.h index ba4b1b93ad81..dbf37704c070 100644 --- a/libsolidity/codegen/ir/IRVariable.h +++ b/libsolidity/codegen/ir/IRVariable.h @@ -69,10 +69,11 @@ class IRVariable /// The returned IRVariable is itself typed with the type of the stack slot as defined /// in ``m_type.stackItems()`` and may again occupy multiple stack slots. IRVariable part(std::string const& _slot) const; -private: + /// @returns a vector containing the names of the stack slots of the variable. std::vector stackSlots() const; +private: /// @returns a name consisting of the base name appended with an underscore and @æ _suffix, /// unless @a _suffix is empty, in which case the base name itself is returned. std::string suffixedName(std::string const& _suffix) const; diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index 13a19694b194..952eb1c50253 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -21,8 +21,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::util; @@ -44,6 +42,7 @@ BMC::BMC( if (_enabledSolvers.some()) if (!_smtlib2Responses.empty()) m_errorReporter.warning( + 5622_error, "SMT-LIB2 query responses were given in the auxiliary input, " "but this Solidity binary uses an SMT solver (Z3/CVC4) directly." "These responses will be ignored." @@ -74,6 +73,7 @@ void BMC::analyze(SourceUnit const& _source, set _safeAsserti { m_noSolverWarning = true; m_outerErrorReporter.warning( + 8084_error, SourceLocation(), "BMC analysis was not possible since no integrated SMT solver (Z3 or CVC4) was found." ); @@ -467,6 +467,7 @@ void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall) inlineFunctionCall(_funCall); else if (funType.kind() == FunctionType::Kind::Internal) m_errorReporter.warning( + 5729_error, _funCall.location(), "Assertion checker does not yet implement this type of function call." ); @@ -591,8 +592,7 @@ void BMC::checkConstantCondition(BMCVerificationTarget& _target) *_target.expression, _target.constraints, _target.value, - _target.callStack, - "Condition is always $VALUE." + _target.callStack ); } @@ -610,6 +610,8 @@ void BMC::checkUnderflow(BMCVerificationTarget& _target, smt::Expression const& _target.callStack, _target.modelExpressions, _target.expression->location(), + 4144_error, + 8312_error, "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ")", "", &_target.value @@ -630,6 +632,8 @@ void BMC::checkOverflow(BMCVerificationTarget& _target, smt::Expression const& _ _target.callStack, _target.modelExpressions, _target.expression->location(), + 2661_error, + 8065_error, "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ")", "", &_target.value @@ -644,6 +648,8 @@ void BMC::checkDivByZero(BMCVerificationTarget& _target) _target.callStack, _target.modelExpressions, _target.expression->location(), + 3046_error, + 5272_error, "Division by zero", "", &_target.value @@ -658,6 +664,8 @@ void BMC::checkBalance(BMCVerificationTarget& _target) _target.callStack, _target.modelExpressions, _target.expression->location(), + 1236_error, + 4010_error, "Insufficient funds", "address(this).balance" ); @@ -672,6 +680,8 @@ void BMC::checkAssert(BMCVerificationTarget& _target) _target.callStack, _target.modelExpressions, _target.expression->location(), + 4661_error, + 7812_error, "Assertion violation" ); } @@ -702,9 +712,11 @@ void BMC::addVerificationTarget( void BMC::checkCondition( smt::Expression _condition, - vector const& callStack, + vector const& _callStack, pair, vector> const& _modelExpressions, SourceLocation const& _location, + ErrorId _errorHappens, + ErrorId _errorMightHappen, string const& _description, string const& _additionalValueName, smt::Expression const* _additionalValue @@ -716,7 +728,7 @@ void BMC::checkCondition( vector expressionsToEvaluate; vector expressionNames; tie(expressionsToEvaluate, expressionNames) = _modelExpressions; - if (callStack.size()) + if (_callStack.size()) if (_additionalValue) { expressionsToEvaluate.emplace_back(*_additionalValue); @@ -747,7 +759,7 @@ void BMC::checkCondition( { std::ostringstream message; message << _description << " happens here"; - if (callStack.size()) + if (_callStack.size()) { std::ostringstream modelMessage; modelMessage << " for:\n"; @@ -760,30 +772,31 @@ void BMC::checkCondition( for (auto const& eval: sortedModel) modelMessage << " " << eval.first << " = " << eval.second << "\n"; m_errorReporter.warning( + _errorHappens, _location, message.str(), SecondarySourceLocation().append(modelMessage.str(), SourceLocation{}) - .append(SMTEncoder::callStackMessage(callStack)) + .append(SMTEncoder::callStackMessage(_callStack)) .append(move(secondaryLocation)) ); } else { message << "."; - m_errorReporter.warning(_location, message.str(), secondaryLocation); + m_errorReporter.warning(6084_error, _location, message.str(), secondaryLocation); } break; } case smt::CheckResult::UNSATISFIABLE: break; case smt::CheckResult::UNKNOWN: - m_errorReporter.warning(_location, _description + " might happen here.", secondaryLocation); + m_errorReporter.warning(_errorMightHappen, _location, _description + " might happen here.", secondaryLocation); break; case smt::CheckResult::CONFLICTING: - m_errorReporter.warning(_location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_errorReporter.warning(1584_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); break; case smt::CheckResult::ERROR: - m_errorReporter.warning(_location, "Error trying to invoke SMT solver."); + m_errorReporter.warning(1823_error, _location, "Error trying to invoke SMT solver."); break; } @@ -794,8 +807,7 @@ void BMC::checkBooleanNotConstant( Expression const& _condition, smt::Expression const& _constraints, smt::Expression const& _value, - vector const& _callStack, - string const& _description + vector const& _callStack ) { // Do not check for const-ness if this is a constant. @@ -813,9 +825,9 @@ void BMC::checkBooleanNotConstant( m_interface->pop(); if (positiveResult == smt::CheckResult::ERROR || negatedResult == smt::CheckResult::ERROR) - m_errorReporter.warning(_condition.location(), "Error trying to invoke SMT solver."); + m_errorReporter.warning(8592_error, _condition.location(), "Error trying to invoke SMT solver."); else if (positiveResult == smt::CheckResult::CONFLICTING || negatedResult == smt::CheckResult::CONFLICTING) - m_errorReporter.warning(_condition.location(), "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_errorReporter.warning(3356_error, _condition.location(), "At least two SMT solvers provided conflicting answers. Results might not be sound."); else if (positiveResult == smt::CheckResult::SATISFIABLE && negatedResult == smt::CheckResult::SATISFIABLE) { // everything fine. @@ -825,24 +837,25 @@ void BMC::checkBooleanNotConstant( // can't do anything. } else if (positiveResult == smt::CheckResult::UNSATISFIABLE && negatedResult == smt::CheckResult::UNSATISFIABLE) - m_errorReporter.warning(_condition.location(), "Condition unreachable.", SMTEncoder::callStackMessage(_callStack)); + m_errorReporter.warning(2512_error, _condition.location(), "Condition unreachable.", SMTEncoder::callStackMessage(_callStack)); else { - string value; + string description; if (positiveResult == smt::CheckResult::SATISFIABLE) { solAssert(negatedResult == smt::CheckResult::UNSATISFIABLE, ""); - value = "true"; + description = "Condition is always true."; } else { solAssert(positiveResult == smt::CheckResult::UNSATISFIABLE, ""); solAssert(negatedResult == smt::CheckResult::SATISFIABLE, ""); - value = "false"; + description = "Condition is always false."; } m_errorReporter.warning( + 6838_error, _condition.location(), - boost::algorithm::replace_all_copy(_description, "$VALUE", value), + description, SMTEncoder::callStackMessage(_callStack) ); } @@ -862,7 +875,7 @@ BMC::checkSatisfiableAndGenerateModel(vector const& _expression string description("Error querying SMT solver"); if (_e.comment()) description += ": " + *_e.comment(); - m_errorReporter.warning(description); + m_errorReporter.warning(8140_error, description); result = smt::CheckResult::ERROR; } diff --git a/libsolidity/formal/BMC.h b/libsolidity/formal/BMC.h index f4b427edeb24..8b30f073d273 100644 --- a/libsolidity/formal/BMC.h +++ b/libsolidity/formal/BMC.h @@ -44,6 +44,7 @@ using solidity::util::h256; namespace solidity::langutil { class ErrorReporter; +struct ErrorId; struct SourceLocation; } @@ -144,22 +145,22 @@ class BMC: public SMTEncoder /// Check that a condition can be satisfied. void checkCondition( smt::Expression _condition, - std::vector const& callStack, + std::vector const& _callStack, std::pair, std::vector> const& _modelExpressions, langutil::SourceLocation const& _location, + langutil::ErrorId _errorHappens, + langutil::ErrorId _errorMightHappen, std::string const& _description, std::string const& _additionalValueName = "", smt::Expression const* _additionalValue = nullptr ); /// Checks that a boolean condition is not constant. Do not warn if the expression /// is a literal constant. - /// @param _description the warning string, $VALUE will be replaced by the constant value. void checkBooleanNotConstant( Expression const& _condition, smt::Expression const& _constraints, smt::Expression const& _value, - std::vector const& _callStack, - std::string const& _description + std::vector const& _callStack ); std::pair> checkSatisfiableAndGenerateModel(std::vector const& _expressionsToEvaluate); diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index 59e77d7cd90b..1453df34f3e3 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -965,10 +965,10 @@ pair> CHC::query(smt::Expression const& _query, case smt::CheckResult::UNKNOWN: break; case smt::CheckResult::CONFLICTING: - m_outerErrorReporter.warning(_location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_outerErrorReporter.warning(1988_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); break; case smt::CheckResult::ERROR: - m_outerErrorReporter.warning(_location, "Error trying to invoke SMT solver."); + m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver."); break; } return {result, values}; diff --git a/libsolidity/formal/CHCSmtLib2Interface.cpp b/libsolidity/formal/CHCSmtLib2Interface.cpp index 1b58b791eb11..4b52b7d5adca 100644 --- a/libsolidity/formal/CHCSmtLib2Interface.cpp +++ b/libsolidity/formal/CHCSmtLib2Interface.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 9003d26ce94c..8760c7b6b8e0 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -266,6 +266,7 @@ void SMTEncoder::endVisit(FunctionDefinition const&) bool SMTEncoder::visit(InlineAssembly const& _inlineAsm) { m_errorReporter.warning( + 7737_error, _inlineAsm.location(), "Assertion checker does not support inline assembly." ); @@ -325,6 +326,7 @@ void SMTEncoder::endVisit(VariableDeclarationStatement const& _varDecl) } else m_errorReporter.warning( + 7186_error, _varDecl.location(), "Assertion checker does not yet implement such variable declarations." ); @@ -350,6 +352,7 @@ void SMTEncoder::endVisit(Assignment const& _assignment) m_context.newValue(*varDecl); m_errorReporter.warning( + 9149_error, _assignment.location(), "Assertion checker does not yet implement this assignment operator." ); @@ -409,6 +412,7 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) m_errorReporter.warning( + 2177_error, _tuple.location(), "Assertion checker does not yet implement inline arrays." ); @@ -493,6 +497,7 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) } else m_errorReporter.warning( + 1950_error, _op.location(), "Assertion checker does not yet implement such increments / decrements." ); @@ -522,6 +527,7 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) arrayIndexAssignment(_op.subExpression(), symbVar->currentValue()); else m_errorReporter.warning( + 2683_error, _op.location(), "Assertion checker does not yet implement \"delete\" for this expression." ); @@ -530,6 +536,7 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) } default: m_errorReporter.warning( + 3682_error, _op.location(), "Assertion checker does not yet implement this operator." ); @@ -568,6 +575,7 @@ void SMTEncoder::endVisit(BinaryOperation const& _op) compareOperation(_op); else m_errorReporter.warning( + 3876_error, _op.location(), "Assertion checker does not yet implement this operator." ); @@ -580,6 +588,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) if (_funCall.annotation().kind == FunctionCallKind::StructConstructorCall) { m_errorReporter.warning( + 4639_error, _funCall.location(), "Assertion checker does not yet implement this expression." ); @@ -639,6 +648,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) } default: m_errorReporter.warning( + 4588_error, _funCall.location(), "Assertion checker does not yet implement this type of function call." ); @@ -771,6 +781,7 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall) } m_errorReporter.warning( + 5084_error, _funCall.location(), "Type conversion is not yet fully supported and might yield false positives." ); @@ -800,6 +811,7 @@ void SMTEncoder::endVisit(Literal const& _literal) else { m_errorReporter.warning( + 7885_error, _literal.location(), "Assertion checker does not yet support the type of this literal (" + _literal.annotation().type->toString() + @@ -850,6 +862,7 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) accessedName = identifier->name(); else m_errorReporter.warning( + 9551_error, _memberAccess.location(), "Assertion checker does not yet support this expression." ); @@ -879,6 +892,7 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) } else m_errorReporter.warning( + 7650_error, _memberAccess.location(), "Assertion checker does not yet support this expression." ); @@ -903,6 +917,7 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess) if (varDecl->type()->category() == Type::Category::FixedBytes) { m_errorReporter.warning( + 7989_error, _indexAccess.location(), "Assertion checker does not yet support index accessing fixed bytes." ); @@ -917,6 +932,7 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess) else { m_errorReporter.warning( + 9118_error, _indexAccess.location(), "Assertion checker does not yet implement this expression." ); @@ -940,6 +956,7 @@ void SMTEncoder::endVisit(IndexRangeAccess const& _indexRangeAccess) { createExpr(_indexRangeAccess); m_errorReporter.warning( + 2923_error, _indexRangeAccess.location(), "Assertion checker does not yet implement this expression." ); @@ -1019,6 +1036,7 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smt::Expression c else { m_errorReporter.warning( + 9056_error, _expr.location(), "Assertion checker does not yet implement this expression." ); @@ -1034,6 +1052,7 @@ void SMTEncoder::defineGlobalVariable(string const& _name, Expression const& _ex bool abstract = m_context.createGlobalSymbol(_name, _expr); if (abstract) m_errorReporter.warning( + 1695_error, _expr.location(), "Assertion checker does not yet support this global variable." ); @@ -1087,6 +1106,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op) } default: m_errorReporter.warning( + 5188_error, _op.location(), "Assertion checker does not yet implement this operator." ); @@ -1094,6 +1114,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op) } else m_errorReporter.warning( + 9011_error, _op.location(), "Assertion checker does not yet implement this operator for type " + type->richIdentifier() + "." ); @@ -1185,6 +1206,7 @@ void SMTEncoder::compareOperation(BinaryOperation const& _op) } else m_errorReporter.warning( + 7229_error, _op.location(), "Assertion checker does not yet implement the type " + _op.annotation().commonType->toString() + " for comparisons" ); @@ -1213,6 +1235,7 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op) } else m_errorReporter.warning( + 3263_error, _op.location(), "Assertion checker does not yet implement the type " + _op.annotation().commonType->toString() + " for boolean operations" ); @@ -1245,6 +1268,7 @@ void SMTEncoder::assignment( m_context.newValue(*varDecl); m_errorReporter.warning( + 6191_error, _location, "Assertion checker does not yet implement type " + _type->toString() ); @@ -1272,6 +1296,7 @@ void SMTEncoder::assignment( } else m_errorReporter.warning( + 8182_error, _location, "Assertion checker does not yet implement such assignments." ); @@ -1482,6 +1507,7 @@ bool SMTEncoder::createVariable(VariableDeclaration const& _varDecl) if (abstract) { m_errorReporter.warning( + 8115_error, _varDecl.location(), "Assertion checker does not yet support the type of this variable." ); @@ -1494,7 +1520,7 @@ smt::Expression SMTEncoder::expr(Expression const& _e, TypePointer _targetType) { if (!m_context.knownExpression(_e)) { - m_errorReporter.warning(_e.location(), "Internal error: Expression undefined for SMT solver." ); + m_errorReporter.warning(6031_error, _e.location(), "Internal error: Expression undefined for SMT solver." ); createExpr(_e); } @@ -1506,6 +1532,7 @@ void SMTEncoder::createExpr(Expression const& _e) bool abstract = m_context.createExpression(_e); if (abstract) m_errorReporter.warning( + 8364_error, _e.location(), "Assertion checker does not yet implement type " + _e.annotation().type->toString() ); diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp index 76527baeb40c..339a0a8ad393 100644 --- a/libsolidity/formal/SMTLib2Interface.cpp +++ b/libsolidity/formal/SMTLib2Interface.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index 56e2ecbde778..c00c2f83cd47 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -73,9 +73,10 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) ); abi.emplace(std::move(method)); } - if (_contractDef.constructor()) + FunctionDefinition const* constructor = _contractDef.constructor(); + if (constructor && constructor->visibility() >= Visibility::Public) { - FunctionType constrType(*_contractDef.constructor()); + FunctionType constrType(*constructor); FunctionType const* externalFunctionType = constrType.interfaceFunctionType(); solAssert(!!externalFunctionType, ""); Json::Value method; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 0af68bda7767..e50d8990ab1f 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -67,7 +67,7 @@ #include -#include +#include #include using namespace std; @@ -239,7 +239,7 @@ bool CompilerStack::parse() m_errorReporter.clear(); if (SemVerVersion{string(VersionString)}.isPrerelease()) - m_errorReporter.warning("This is a pre-release compiler version, please do not use it in production."); + m_errorReporter.warning(3805_error, "This is a pre-release compiler version, please do not use it in production."); Parser parser{m_errorReporter, m_evmVersion, m_parserErrorRecovery}; @@ -949,6 +949,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string else { m_errorReporter.parserError( + 6275_error, import->location(), string("Source \"" + importPath + "\" not found: " + result.responseOrErrorMessage) ); @@ -1110,6 +1111,7 @@ void CompilerStack::compileContract( compiledContract.runtimeObject.bytecode.size() > 0x6000 ) m_errorReporter.warning( + 5574_error, _contract.location(), "Contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). " "This contract may not be deployable on mainnet. " @@ -1234,6 +1236,8 @@ string CompilerStack::createMetadata(Contract const& _contract) const solAssert(s.second.scanner, "Scanner not available"); meta["sources"][s.first]["keccak256"] = "0x" + toHex(s.second.keccak256().asBytes()); + if (optional licenseString = s.second.ast->licenseString()) + meta["sources"][s.first]["license"] = *licenseString; if (m_metadataLiteralSources) meta["sources"][s.first]["content"] = s.second.scanner->source(); else diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp index b78e46081e82..5e51696ec8ba 100644 --- a/libsolidity/interface/Natspec.cpp +++ b/libsolidity/interface/Natspec.cpp @@ -99,16 +99,14 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef) if (auto fun = dynamic_cast(&it.second->declaration())) { Json::Value method(devDocumentation(fun->annotation().docTags)); - if (!method.empty()) - { - // add the function, only if we have any documentation to add - Json::Value jsonReturn = extractReturnParameterDocs(fun->annotation().docTags, *fun); + // add the function, only if we have any documentation to add + Json::Value jsonReturn = extractReturnParameterDocs(fun->annotation().docTags, *fun); - if (!jsonReturn.empty()) - method["returns"] = jsonReturn; + if (!jsonReturn.empty()) + method["returns"] = jsonReturn; + if (!method.empty()) methods[it.second->externalSignature()] = method; - } } } diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 15989dcf32b3..0abc867e8602 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -31,8 +31,7 @@ #include #include -#include -#include +#include #include #include @@ -491,7 +490,7 @@ std::optional checkOutputSelection(Json::Value const& _outputSelect } /// Validates the optimizer settings and returns them in a parsed object. /// On error returns the json-formatted error message. -boost::variant parseOptimizerSettings(Json::Value const& _jsonInput) +std::variant parseOptimizerSettings(Json::Value const& _jsonInput) { if (auto result = checkOptimizerKeys(_jsonInput)) return *result; @@ -552,7 +551,7 @@ boost::variant parseOptimizerSettings(Json::Valu } -boost::variant StandardCompiler::parseInput(Json::Value const& _input) +std::variant StandardCompiler::parseInput(Json::Value const& _input) { InputsAndSettings ret; @@ -740,10 +739,10 @@ boost::variant StandardCompile if (settings.isMember("optimizer")) { auto optimiserSettings = parseOptimizerSettings(settings["optimizer"]); - if (optimiserSettings.type() == typeid(Json::Value)) - return boost::get(std::move(optimiserSettings)); // was an error + if (std::holds_alternative(optimiserSettings)) + return std::get(std::move(optimiserSettings)); // was an error else - ret.optimiserSettings = boost::get(std::move(optimiserSettings)); + ret.optimiserSettings = std::get(std::move(optimiserSettings)); } Json::Value jsonLibraries = settings.get("libraries", Json::Value(Json::objectValue)); @@ -1155,9 +1154,9 @@ Json::Value StandardCompiler::compile(Json::Value const& _input) noexcept try { auto parsed = parseInput(_input); - if (parsed.type() == typeid(Json::Value)) - return boost::get(std::move(parsed)); - InputsAndSettings settings = boost::get(std::move(parsed)); + if (std::holds_alternative(parsed)) + return std::get(std::move(parsed)); + InputsAndSettings settings = std::get(std::move(parsed)); if (settings.language == "Solidity") return compileSolidity(std::move(settings)); else if (settings.language == "Yul") diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 885417d8bd56..d1a1489c3df9 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -24,9 +24,9 @@ #include -#include #include #include +#include namespace solidity::frontend { @@ -73,7 +73,7 @@ class StandardCompiler: boost::noncopyable /// Parses the input json (and potentially invokes the read callback) and either returns /// it in condensed form or an error as a json object. - boost::variant parseInput(Json::Value const& _input); + std::variant parseInput(Json::Value const& _input); Json::Value compileSolidity(InputsAndSettings _inputsAndSettings); Json::Value compileYul(InputsAndSettings _inputsAndSettings); diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index fb1468197c1a..b8238554f8a7 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -195,5 +195,5 @@ void DocStringParser::newTag(string const& _tagName) void DocStringParser::appendError(string const& _description) { m_errorsOccurred = true; - m_errorReporter->docstringParsingError(_description); + m_errorReporter->docstringParsingError(9440_error, _description); } diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index c6da9a55b492..7ae22dc70343 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -30,8 +30,11 @@ #include #include #include +#include +#include #include #include +#include using namespace std; using namespace solidity::langutil; @@ -79,6 +82,7 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) m_recursionDepth = 0; m_scanner = _scanner; ASTNodeFactory nodeFactory(*this); + vector> nodes; while (m_scanner->currentToken() != Token::EOS) { @@ -103,11 +107,11 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) nodes.push_back(parseEnumDefinition()); break; default: - fatalParserError(string("Expected pragma, import directive or contract/interface/library/struct/enum definition.")); + fatalParserError(7858_error, "Expected pragma, import directive or contract/interface/library/struct/enum definition."); } } solAssert(m_recursionDepth == 0, ""); - return nodeFactory.createNode(nodes); + return nodeFactory.createNode(findLicenseString(nodes), nodes); } catch (FatalError const&) { @@ -128,9 +132,10 @@ void Parser::parsePragmaVersion(SourceLocation const& _location, vector c // so we don't need to report anything here. if (!m_parserErrorRecovery) m_errorReporter.fatalParserError( + 5333_error, _location, "Source file requires different compiler version (current compiler is " + - string(VersionString) + " - note that nightly builds are considered to be " + string(VersionString) + ") - note that nightly builds are considered to be " "strictly less than the released version" ); } @@ -162,7 +167,7 @@ ASTPointer Parser::parsePragmaDirective() { Token token = m_scanner->currentToken(); if (token == Token::Illegal) - parserError("Token incompatible with Solidity parser as part of pragma directive."); + parserError(6281_error, "Token incompatible with Solidity parser as part of pragma directive."); else { string literal = m_scanner->currentLiteral(); @@ -240,18 +245,18 @@ ASTPointer Parser::parseImportDirective() unitAlias = expectIdentifierToken(); } else - fatalParserError("Expected string literal (path), \"*\" or alias list."); + fatalParserError(9478_error, "Expected string literal (path), \"*\" or alias list."); // "from" is not a keyword but parsed as an identifier because of backwards // compatibility and because it is a really common word. if (m_scanner->currentToken() != Token::Identifier || m_scanner->currentLiteral() != "from") - fatalParserError("Expected \"from\"."); + fatalParserError(8208_error, "Expected \"from\"."); m_scanner->next(); if (m_scanner->currentToken() != Token::StringLiteral) - fatalParserError("Expected import path."); + fatalParserError(6845_error, "Expected import path."); path = getLiteralAndAdvance(); } if (path->empty()) - fatalParserError("Import path cannot be empty."); + fatalParserError(6326_error, "Import path cannot be empty."); nodeFactory.markEndPosition(); expectToken(Token::Semicolon); return nodeFactory.createNode(path, unitAlias, move(symbolAliases)); @@ -278,7 +283,7 @@ std::pair Parser::parseContractKind() kind = ContractKind::Library; break; default: - parserError("Expected keyword \"contract\", \"interface\" or \"library\"."); + parserError(3515_error, "Expected keyword \"contract\", \"interface\" or \"library\"."); return std::make_pair(ContractKind::Contract, abstract); } m_scanner->next(); @@ -343,7 +348,7 @@ ASTPointer Parser::parseContractDefinition() else if (currentTokenValue == Token::Using) subNodes.push_back(parseUsingDirective()); else - fatalParserError(string("Function, variable, struct or modifier declaration expected.")); + fatalParserError(9182_error, "Function, variable, struct or modifier declaration expected."); } } catch (FatalError const&) @@ -462,6 +467,7 @@ StateMutability Parser::parseStateMutability() case Token::Constant: stateMutability = StateMutability::View; parserError( + 7698_error, "The state mutability modifier \"constant\" was removed in version 0.5.0. " "Use \"view\" or \"pure\" instead." ); @@ -494,11 +500,12 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari // Detect this and return early. if (_isStateVariable && (result.visibility == Visibility::External || result.visibility == Visibility::Internal)) break; - parserError(string( + parserError( + 9439_error, "Visibility already specified as \"" + Declaration::visibilityToString(result.visibility) + "\"." - )); + ); m_scanner->next(); } else @@ -508,11 +515,12 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari { if (result.stateMutability != StateMutability::NonPayable) { - parserError(string( + parserError( + 9680_error, "State mutability already specified as \"" + stateMutabilityToString(result.stateMutability) + "\"." - )); + ); m_scanner->next(); } else @@ -521,14 +529,14 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari else if (!_isStateVariable && token == Token::Override) { if (result.overrides) - parserError("Override already specified."); + parserError(1827_error, "Override already specified."); result.overrides = parseOverrideSpecifier(); } else if (!_isStateVariable && token == Token::Virtual) { if (result.isVirtual) - parserError("Virtual already specified."); + parserError(6879_error, "Virtual already specified."); result.isVirtual = true; m_scanner->next(); @@ -576,9 +584,9 @@ ASTPointer Parser::parseFunctionDefinition() "the \"function\" keyword to define it." }; if (m_scanner->currentToken() == Token::Constructor) - parserError(message); + parserError(3323_error, message); else - parserWarning(message); + parserWarning(3445_error, message); m_scanner->next(); } else @@ -659,10 +667,10 @@ ASTPointer Parser::parseEnumDefinition() break; expectToken(Token::Comma); if (m_scanner->currentToken() != Token::Identifier) - fatalParserError(string("Expected identifier after ','")); + fatalParserError(1612_error, "Expected identifier after ','"); } if (members.empty()) - parserError({"enum with no members is not allowed."}); + parserError(3147_error, "enum with no members is not allowed."); nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -689,6 +697,7 @@ ASTPointer Parser::parseVariableDeclaration( if (dynamic_cast(type.get()) && _options.isStateVariable && m_scanner->currentToken() == Token::LBrace) fatalParserError( + 2915_error, "Expected a state variable declaration. If you intended this as a fallback function " "or a function to handle plain ether transactions, use the \"fallback\" keyword " "or the \"receive\" keyword instead." @@ -709,11 +718,12 @@ ASTPointer Parser::parseVariableDeclaration( nodeFactory.markEndPosition(); if (visibility != Visibility::Default) { - parserError(string( + parserError( + 4110_error, "Visibility already specified as \"" + Declaration::visibilityToString(visibility) + "\"." - )); + ); m_scanner->next(); } else @@ -722,7 +732,7 @@ ASTPointer Parser::parseVariableDeclaration( else if (_options.isStateVariable && token == Token::Override) { if (overrides) - parserError("Override already specified."); + parserError(9125_error, "Override already specified."); overrides = parseOverrideSpecifier(); } @@ -734,6 +744,7 @@ ASTPointer Parser::parseVariableDeclaration( { if (mutability != VariableDeclaration::Mutability::Mutable) parserError( + 3109_error, string("Mutability already set to ") + (mutability == VariableDeclaration::Mutability::Constant ? "\"constant\"" : "\"immutable\"") ); @@ -745,9 +756,9 @@ ASTPointer Parser::parseVariableDeclaration( else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Unspecified) - parserError(string("Location already specified.")); + parserError(3548_error, "Location already specified."); else if (!type) - parserError(string("Location specifier needs explicit type name.")); + parserError(7439_error, "Location specifier needs explicit type name."); else { switch (token) @@ -836,13 +847,13 @@ ASTPointer Parser::parseModifierDefinition() if (m_scanner->currentToken() == Token::Override) { if (overrides) - parserError("Override already specified."); + parserError(9102_error, "Override already specified."); overrides = parseOverrideSpecifier(); } else if (m_scanner->currentToken() == Token::Virtual) { if (isVirtual) - parserError("Virtual already specified."); + parserError(2662_error, "Virtual already specified."); isVirtual = true; m_scanner->next(); @@ -990,7 +1001,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) } else { - parserError("State mutability can only be specified for address types."); + parserError(9106_error, "State mutability can only be specified for address types."); m_scanner->next(); } } @@ -999,7 +1010,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::Var) { if (!_allowVar) - parserError(string("Expected explicit type name.")); + parserError(7059_error, "Expected explicit type name."); m_scanner->next(); } else if (token == Token::Function) @@ -1009,7 +1020,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::Identifier) type = parseUserDefinedTypeName(); else - fatalParserError(string("Expected type name")); + fatalParserError(3546_error, "Expected type name"); if (type) // Parse "[...]" postfixes for arrays. @@ -1052,7 +1063,7 @@ ASTPointer Parser::parseMapping() m_scanner->next(); } else - fatalParserError(string("Expected elementary type name or identifier for mapping key type")); + fatalParserError(1005_error, "Expected elementary type name or identifier for mapping key type"); expectToken(Token::Arrow); bool const allowVar = false; ASTPointer valueType = parseTypeName(allowVar); @@ -1078,7 +1089,7 @@ ASTPointer Parser::parseParameterList( while (m_scanner->currentToken() != Token::RParen) { if (m_scanner->currentToken() == Token::Comma && m_scanner->peekNextToken() == Token::RParen) - fatalParserError("Unexpected trailing comma in parameter list."); + fatalParserError(7591_error, "Unexpected trailing comma in parameter list."); expectToken(Token::Comma); parameters.push_back(parseVariableDeclaration(options)); } @@ -1213,7 +1224,7 @@ ASTPointer Parser::parseInlineAssembly(ASTPointer con if (m_scanner->currentToken() == Token::StringLiteral) { if (m_scanner->currentLiteral() != "evmasm") - fatalParserError("Only \"evmasm\" supported."); + fatalParserError(4531_error, "Only \"evmasm\" supported."); // This can be used in the future to set the dialect. m_scanner->next(); } @@ -1376,7 +1387,7 @@ ASTPointer Parser::parseEmitStatement(ASTPointer const ASTNodeFactory eventCallNodeFactory(*this); if (m_scanner->currentToken() != Token::Identifier) - fatalParserError("Expected event name or path."); + fatalParserError(5620_error, "Expected event name or path."); IndexAccessedPath iap; while (true) @@ -1844,7 +1855,7 @@ ASTPointer Parser::parsePrimaryExpression() nodeFactory.markEndPosition(); m_scanner->next(); if (m_scanner->currentToken() == Token::Illegal) - fatalParserError(to_string(m_scanner->currentError())); + fatalParserError(5428_error, to_string(m_scanner->currentError())); expression = nodeFactory.createNode(token, make_shared(literal)); break; } @@ -1875,7 +1886,7 @@ ASTPointer Parser::parsePrimaryExpression() if (m_scanner->currentToken() != Token::Comma && m_scanner->currentToken() != oppositeToken) components.push_back(parseExpression()); else if (isArray) - parserError("Expected expression (inline array elements cannot be omitted)."); + parserError(4799_error, "Expected expression (inline array elements cannot be omitted)."); else components.push_back(ASTPointer()); @@ -1890,7 +1901,7 @@ ASTPointer Parser::parsePrimaryExpression() break; } case Token::Illegal: - fatalParserError(to_string(m_scanner->currentError())); + fatalParserError(8936_error, to_string(m_scanner->currentError())); break; default: if (TokenTraits::isElementaryTypeName(token)) @@ -1906,7 +1917,7 @@ ASTPointer Parser::parsePrimaryExpression() m_scanner->next(); } else - fatalParserError(string("Expected primary expression.")); + fatalParserError(6933_error, "Expected primary expression."); break; } return expression; @@ -1964,7 +1975,7 @@ pair>, vector>> Parser::pars m_scanner->peekNextToken() == Token::RBrace ) { - parserError("Unexpected trailing comma."); + parserError(2074_error, "Unexpected trailing comma."); m_scanner->next(); } @@ -1974,6 +1985,60 @@ pair>, vector>> Parser::pars return ret; } +optional Parser::findLicenseString(std::vector> const& _nodes) +{ + // We circumvent the scanner here, because it skips non-docstring comments. + static regex const licenseRegex("SPDX-License-Identifier:\\s*([a-zA-Z0-9 ()+.-]+)"); + + // Search inside all parts of the source not covered by parsed nodes. + // This will leave e.g. "global comments". + string const& source = m_scanner->source(); + using iter = decltype(source.begin()); + vector> sequencesToSearch; + sequencesToSearch.emplace_back(source.begin(), source.end()); + for (ASTPointer const& node: _nodes) + if (node->location().hasText()) + { + sequencesToSearch.back().second = source.begin() + node->location().start; + sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end()); + } + + vector matches; + for (auto const& [start, end]: sequencesToSearch) + { + smatch match; + if (regex_search(start, end, match, licenseRegex)) + { + string license{boost::trim_copy(string(match[1]))}; + if (!license.empty()) + matches.emplace_back(std::move(license)); + } + } + + if (matches.size() == 1) + return matches.front(); + else if (matches.empty()) + parserWarning( + 1878_error, + {-1, -1, m_scanner->charStream()}, + "SPDX license identifier not provided in source file. " + "Before publishing, consider adding a comment containing " + "\"SPDX-License-Identifier: \" to each source file. " + "Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. " + "Please see https://spdx.org for more information." + ); + else + parserError( + 3716_error, + {-1, -1, m_scanner->charStream()}, + "Multiple SPDX license identifiers found in source file. " + "Use \"AND\" or \"OR\" to combine multiple licenses. " + "Please see https://spdx.org for more information." + ); + + return {}; +} + Parser::LookAheadInfo Parser::peekStatementType() const { // Distinguish between variable declaration (and potentially assignment) and expression statement @@ -2083,7 +2148,7 @@ ASTPointer Parser::typeNameFromIndexAccessStructure(Parser::IndexAcces for (auto const& lengthExpression: _iap.indices) { if (lengthExpression.end) - parserError(lengthExpression.location, "Expected array length expression."); + parserError(5464_error, lengthExpression.location, "Expected array length expression."); nodeFactory.setLocation(lengthExpression.location); type = nodeFactory.createNode(type, lengthExpression.start); } diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 25bb2b93f401..f66754045585 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -175,6 +175,8 @@ class Parser: public langutil::ParserBase bool empty() const; }; + std::optional findLicenseString(std::vector> const& _nodes); + /// Returns the next AST node ID int64_t nextID() { return ++m_currentNodeID; } diff --git a/libsolutil/CommonData.cpp b/libsolutil/CommonData.cpp index 2024a1b1f9fb..bb1a7696c974 100644 --- a/libsolutil/CommonData.cpp +++ b/libsolutil/CommonData.cpp @@ -188,5 +188,39 @@ string solidity::util::formatAsStringOrNumber(string const& _value) if (c <= 0x1f || c >= 0x7f || c == '"') return "0x" + h256(_value, h256::AlignLeft).hex(); - return "\"" + _value + "\""; + return escapeAndQuoteString(_value); +} + + +string solidity::util::escapeAndQuoteString(string const& _input) +{ + string out; + + for (char c: _input) + if (c == '\\') + out += "\\\\"; + else if (c == '"') + out += "\\\""; + else if (c == '\b') + out += "\\b"; + else if (c == '\f') + out += "\\f"; + else if (c == '\n') + out += "\\n"; + else if (c == '\r') + out += "\\r"; + else if (c == '\t') + out += "\\t"; + else if (c == '\v') + out += "\\v"; + else if (!isprint(c, locale::classic())) + { + ostringstream o; + o << "\\x" << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c); + out += o.str(); + } + else + out += c; + + return "\"" + std::move(out) + "\""; } diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index bd1133511dfb..adac1fb051e8 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -460,6 +460,10 @@ bool isValidDecimal(std::string const& _string); /// _value cannot be longer than 32 bytes. std::string formatAsStringOrNumber(std::string const& _value); +/// @returns a string with the usual backslash-escapes for non-ASCII +/// characters and surrounded by '"'-characters. +std::string escapeAndQuoteString(std::string const& _input); + template bool containerEqual(Container const& _lhs, Container const& _rhs, Compare&& _compare) { diff --git a/libsolutil/CommonIO.h b/libsolutil/CommonIO.h index be763c42f2c1..38c8f564a43b 100644 --- a/libsolutil/CommonIO.h +++ b/libsolutil/CommonIO.h @@ -24,7 +24,6 @@ #pragma once #include -#include #include #include diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index ca3f88c753e7..2edd4dc38fec 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -306,11 +306,15 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) _funCall.functionName.location, "Function expects direct literals as arguments." ); - else if (!m_dataNames.count(std::get(arg).value)) - typeError( - _funCall.functionName.location, - "Unknown data object \"" + std::get(arg).value.str() + "\"." - ); + else if ( + _funCall.functionName.name.str() == "datasize" || + _funCall.functionName.name.str() == "dataoffset" + ) + if (!m_dataNames.count(std::get(arg).value)) + typeError( + _funCall.functionName.location, + "Unknown data object \"" + std::get(arg).value.str() + "\"." + ); } } std::reverse(argTypes.begin(), argTypes.end()); @@ -523,7 +527,7 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation // Similarly we assume bitwise shifting and create2 go together. yulAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), ""); - auto errorForVM = [=](string const& vmKindMessage) { + auto errorForVM = [&](string const& vmKindMessage) { typeError( _location, "The \"" + @@ -579,6 +583,7 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation ) { m_errorReporter.error( + 4316_error, Error::Type::SyntaxError, _location, "Jump instructions and labels are low-level EVM features that can lead to " @@ -595,13 +600,13 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation void AsmAnalyzer::typeError(SourceLocation const& _location, string const& _description) { - m_errorReporter.typeError(_location, _description); + m_errorReporter.typeError(7569_error, _location, _description); m_success = false; } void AsmAnalyzer::declarationError(SourceLocation const& _location, string const& _description) { - m_errorReporter.declarationError(_location, _description); + m_errorReporter.declarationError(9595_error, _location, _description); m_success = false; } diff --git a/libyul/AsmJsonConverter.h b/libyul/AsmJsonConverter.h index 360fa6a364d0..b350689fc515 100644 --- a/libyul/AsmJsonConverter.h +++ b/libyul/AsmJsonConverter.h @@ -20,6 +20,8 @@ * Converts inline assembly AST to JSON format */ +#pragma once + #include #include #include diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 758b11d92806..19574446d102 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -122,11 +122,11 @@ Statement Parser::parseStatement() if (currentToken() == Token::Default) _switch.cases.emplace_back(parseCase()); if (currentToken() == Token::Default) - fatalParserError("Only one default case allowed."); + fatalParserError(6931_error, "Only one default case allowed."); else if (currentToken() == Token::Case) - fatalParserError("Case not allowed after default case."); + fatalParserError(4904_error, "Case not allowed after default case."); if (_switch.cases.empty()) - fatalParserError("Switch statement without any cases."); + fatalParserError(2418_error, "Switch statement without any cases."); _switch.location.end = _switch.cases.back().body.location.end; return Statement{move(_switch)}; } @@ -151,7 +151,7 @@ Statement Parser::parseStatement() { Statement stmt{createWithLocation()}; if (!m_insideFunction) - m_errorReporter.syntaxError(currentLocation(), "Keyword \"leave\" can only be used inside a function."); + m_errorReporter.syntaxError(8149_error, currentLocation(), "Keyword \"leave\" can only be used inside a function."); m_scanner->next(); return stmt; } @@ -184,6 +184,7 @@ Statement Parser::parseStatement() auto const token = currentToken() == Token::Comma ? "," : ":="; fatalParserError( + 2856_error, std::string("Variable name must precede \"") + token + "\"" + @@ -194,7 +195,7 @@ Statement Parser::parseStatement() auto const& identifier = std::get(elementary); if (m_dialect.builtin(identifier.name)) - fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); + fatalParserError(6272_error, "Cannot assign to builtin function \"" + identifier.name.str() + "\"."); variableNames.emplace_back(identifier); @@ -218,7 +219,7 @@ Statement Parser::parseStatement() return Statement{std::move(assignment)}; } default: - fatalParserError("Call or assignment expected."); + fatalParserError(6913_error, "Call or assignment expected."); break; } @@ -250,7 +251,7 @@ Case Parser::parseCase() advance(); ElementaryOperation literal = parseElementaryOperation(); if (!holds_alternative(literal)) - fatalParserError("Literal expected."); + fatalParserError(4805_error, "Literal expected."); _case.value = make_unique(std::get(std::move(literal))); } else @@ -325,6 +326,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() case Token::Bool: case Token::Address: case Token::Var: + case Token::In: { YulString literal{currentLiteral()}; if (m_dialect.builtin(literal)) @@ -352,7 +354,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() break; case Token::Number: if (!isValidNumberLiteral(currentLiteral())) - fatalParserError("Invalid number literal."); + fatalParserError(4828_error, "Invalid number literal."); kind = LiteralKind::Number; break; case Token::TrueLiteral: @@ -381,7 +383,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() break; } default: - fatalParserError("Literal or identifier expected."); + fatalParserError(1856_error, "Literal or identifier expected."); } return ret; } @@ -416,6 +418,7 @@ FunctionDefinition Parser::parseFunctionDefinition() if (m_currentForLoopComponent == ForLoopComponent::ForLoopPre) m_errorReporter.syntaxError( + 3441_error, currentLocation(), "Functions cannot be defined inside a for-loop init block." ); @@ -470,7 +473,7 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) else if (holds_alternative(_initialOp)) ret = std::move(std::get(_initialOp)); else - fatalParserError("Function name expected."); + fatalParserError(9980_error, "Function name expected."); expectToken(Token::LParen); if (currentToken() != Token::RParen) @@ -515,6 +518,7 @@ YulString Parser::expectAsmIdentifier() case Token::Bool: case Token::Identifier: case Token::Var: + case Token::In: break; default: expectToken(Token::Identifier); @@ -522,7 +526,7 @@ YulString Parser::expectAsmIdentifier() } if (m_dialect.builtin(name)) - fatalParserError("Cannot use builtin function name \"" + name.str() + "\" as identifier name."); + fatalParserError(5568_error, "Cannot use builtin function name \"" + name.str() + "\" as identifier name."); advance(); return name; } @@ -532,13 +536,13 @@ void Parser::checkBreakContinuePosition(string const& _which) switch (m_currentForLoopComponent) { case ForLoopComponent::None: - m_errorReporter.syntaxError(currentLocation(), "Keyword \"" + _which + "\" needs to be inside a for-loop body."); + m_errorReporter.syntaxError(2592_error, currentLocation(), "Keyword \"" + _which + "\" needs to be inside a for-loop body."); break; case ForLoopComponent::ForLoopPre: - m_errorReporter.syntaxError(currentLocation(), "Keyword \"" + _which + "\" in for-loop init block is not allowed."); + m_errorReporter.syntaxError(9615_error, currentLocation(), "Keyword \"" + _which + "\" in for-loop init block is not allowed."); break; case ForLoopComponent::ForLoopPost: - m_errorReporter.syntaxError(currentLocation(), "Keyword \"" + _which + "\" in for-loop post block is not allowed."); + m_errorReporter.syntaxError(2461_error, currentLocation(), "Keyword \"" + _which + "\" in for-loop post block is not allowed."); break; case ForLoopComponent::ForLoopBody: break; diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 93fb089edb91..97a7dc3ade61 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -55,33 +55,7 @@ string AsmPrinter::operator()(Literal const& _literal) const break; } - string out; - for (char c: _literal.value.str()) - if (c == '\\') - out += "\\\\"; - else if (c == '"') - out += "\\\""; - else if (c == '\b') - out += "\\b"; - else if (c == '\f') - out += "\\f"; - else if (c == '\n') - out += "\\n"; - else if (c == '\r') - out += "\\r"; - else if (c == '\t') - out += "\\t"; - else if (c == '\v') - out += "\\v"; - else if (!isprint(c, locale::classic())) - { - ostringstream o; - o << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c); - out += "\\x" + o.str(); - } - else - out += c; - return "\"" + out + "\"" + appendTypeName(_literal.type); + return escapeAndQuoteString(_literal.value.str()) + appendTypeName(_literal.type); } string AsmPrinter::operator()(Identifier const& _identifier) const diff --git a/libyul/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp index 4c37bf5ecc7c..90143ba4dd44 100644 --- a/libyul/AsmScopeFiller.cpp +++ b/libyul/AsmScopeFiller.cpp @@ -29,8 +29,6 @@ #include -#include - #include #include @@ -141,6 +139,7 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& { //@TODO secondary location m_errorReporter.declarationError( + 1395_error, _location, "Variable name " + _name.name.str() + " already taken in this scope." ); @@ -161,6 +160,7 @@ bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef) { //@TODO secondary location m_errorReporter.declarationError( + 6052_error, _funDef.location, "Function name " + _funDef.name.str() + " already taken in this scope." ); diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index 74c339f18f7a..7e50fa88e6c6 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -66,7 +66,7 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) RecursionGuard guard(*this); if (currentToken() != Token::Identifier || currentLiteral() != "object") - fatalParserError("Expected keyword \"object\"."); + fatalParserError(4294_error, "Expected keyword \"object\"."); advance(); shared_ptr ret = make_shared(); @@ -83,7 +83,7 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) else if (currentToken() == Token::Identifier && currentLiteral() == "data") parseData(*ret); else - fatalParserError("Expected keyword \"data\" or \"object\" or \"}\"."); + fatalParserError(8143_error, "Expected keyword \"data\" or \"object\" or \"}\"."); } if (_containingObject) addNamedSubObject(*_containingObject, ret->name, ret); @@ -96,7 +96,7 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) shared_ptr ObjectParser::parseCode() { if (currentToken() != Token::Identifier || currentLiteral() != "code") - fatalParserError("Expected keyword \"code\"."); + fatalParserError(4846_error, "Expected keyword \"code\"."); advance(); return parseBlock(); @@ -133,11 +133,11 @@ YulString ObjectParser::parseUniqueName(Object const* _containingObject) expectToken(Token::StringLiteral, false); YulString name{currentLiteral()}; if (name.empty()) - parserError("Object name cannot be empty."); + parserError(3287_error, "Object name cannot be empty."); else if (_containingObject && _containingObject->name == name) - parserError("Object name cannot be the same as the name of the containing object."); + parserError(8311_error, "Object name cannot be the same as the name of the containing object."); else if (_containingObject && _containingObject->subIndexByName.count(name)) - parserError("Object name \"" + name.str() + "\" already exists inside the containing object."); + parserError(8794_error, "Object name \"" + name.str() + "\" already exists inside the containing object."); advance(); return name; } diff --git a/libyul/Utilities.cpp b/libyul/Utilities.cpp index 8789381b7ae1..a797258eb544 100644 --- a/libyul/Utilities.cpp +++ b/libyul/Utilities.cpp @@ -38,9 +38,6 @@ using namespace solidity; using namespace solidity::yul; using namespace solidity::util; -using boost::split; -using boost::is_any_of; - string solidity::yul::reindent(string const& _code) { int constexpr indentationWidth = 4; @@ -55,7 +52,7 @@ string solidity::yul::reindent(string const& _code) }; vector lines; - split(lines, _code, is_any_of("\n")); + boost::split(lines, _code, boost::is_any_of("\n")); for (string& line: lines) boost::trim(line); diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 9187bb88d481..2f86270b0f7e 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -105,6 +105,11 @@ class AbstractAssembly virtual void appendDataSize(SubID _sub) = 0; /// Appends the given data to the assembly and returns its ID. virtual SubID appendData(bytes const& _data) = 0; + + /// Appends loading an immutable variable. + virtual void appendImmutable(std::string const& _identifier) = 0; + /// Appends an assignment to an immutable variable. + virtual void appendImmutableAssignment(std::string const& _identifier) = 0; }; enum class IdentifierContext { LValue, RValue, VariableDeclaration }; diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index a864b0a09977..eefff5b18229 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -172,6 +172,16 @@ AbstractAssembly::SubID EthAssemblyAdapter::appendData(bytes const& _data) return subID; } +void EthAssemblyAdapter::appendImmutable(std::string const& _identifier) +{ + m_assembly.appendImmutable(_identifier); +} + +void EthAssemblyAdapter::appendImmutableAssignment(std::string const& _identifier) +{ + m_assembly.appendImmutableAssignment(_identifier); +} + EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag) { u256 id = _tag.data(); diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index baab37b4c8a9..e126ba2c08d4 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -61,6 +61,9 @@ class EthAssemblyAdapter: public AbstractAssembly void appendDataSize(SubID _sub) override; SubID appendData(bytes const& _data) override; + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + private: static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag); diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 70711ffd610f..47f7509a3902 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -215,6 +215,16 @@ AbstractAssembly::SubID EVMAssembly::appendData(bytes const&) yulAssert(false, "Data not implemented."); } +void EVMAssembly::appendImmutable(std::string const&) +{ + yulAssert(false, "loadimmutable not implemented."); +} + +void EVMAssembly::appendImmutableAssignment(std::string const&) +{ + yulAssert(false, "setimmutable not implemented."); +} + void EVMAssembly::updateReference(size_t pos, size_t size, u256 value) { yulAssert(m_bytecode.size() >= size && pos <= m_bytecode.size() - size, ""); diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index 744d8738b9ab..da4f5c0379f4 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -83,6 +83,9 @@ class EVMAssembly: public AbstractAssembly void appendDataSize(SubID _sub) override; SubID appendData(bytes const& _data) override; + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + /// Resolves references inside the bytecode and returns the linker object. evmasm::LinkerObject finalize(); diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 6ca55821d2d4..a4e19998f80f 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -85,11 +85,11 @@ void VariableReferenceCounter::operator()(Block const& _block) void VariableReferenceCounter::increaseRefIfFound(YulString _variableName) { m_scope->lookup(_variableName, GenericVisitor{ - [=](Scope::Variable const& _var) + [&](Scope::Variable const& _var) { ++m_context.variableReferences[&_var]; }, - [=](Scope::Function const&) { } + [](Scope::Function const&) { } }); } @@ -184,11 +184,13 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) } else { + m_assembly.setSourceLocation(_varDecl.location); int variablesLeft = numVariables; while (variablesLeft--) m_assembly.appendConstant(u256(0)); } + m_assembly.setSourceLocation(_varDecl.location); bool atTopOfStack = true; for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex) { @@ -203,7 +205,6 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) if (atTopOfStack) { m_context->variableStackHeights.erase(&var); - m_assembly.setSourceLocation(_varDecl.location); m_assembly.appendInstruction(evmasm::Instruction::POP); } else @@ -216,7 +217,6 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) int slot = *m_unusedStackSlots.begin(); m_unusedStackSlots.erase(m_unusedStackSlots.begin()); m_context->variableStackHeights[&var] = slot; - m_assembly.setSourceLocation(_varDecl.location); if (int heightDiff = variableHeightDiff(var, varName, true)) m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1)); m_assembly.appendInstruction(evmasm::Instruction::POP); @@ -257,13 +257,9 @@ void CodeTransform::operator()(FunctionCall const& _call) yulAssert(m_scope, ""); if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) - { - builtin->generateCode(_call, m_assembly, m_builtinContext, [&]() { - for (auto const& arg: _call.arguments | boost::adaptors::reversed) - visitExpression(arg); - m_assembly.setSourceLocation(_call.location); + builtin->generateCode(_call, m_assembly, m_builtinContext, [&](Expression const& _expression) { + visitExpression(_expression); }); - } else { m_assembly.setSourceLocation(_call.location); @@ -276,7 +272,7 @@ void CodeTransform::operator()(FunctionCall const& _call) Scope::Function* function = nullptr; yulAssert(m_scope->lookup(_call.functionName.name, GenericVisitor{ - [=](Scope::Variable&) { yulAssert(false, "Expected function name."); }, + [](Scope::Variable&) { yulAssert(false, "Expected function name."); }, [&](Scope::Function& _function) { function = &_function; } }), "Function name not found."); yulAssert(function, ""); @@ -300,7 +296,7 @@ void CodeTransform::operator()(Identifier const& _identifier) // First search internals, then externals. yulAssert(m_scope, ""); if (m_scope->lookup(_identifier.name, GenericVisitor{ - [=](Scope::Variable& _var) + [&](Scope::Variable& _var) { // TODO: opportunity for optimization: Do not DUP if this is the last reference // to the top most element of the stack @@ -311,7 +307,7 @@ void CodeTransform::operator()(Identifier const& _identifier) m_assembly.appendConstant(u256(0)); decreaseReference(_identifier.name, _var); }, - [=](Scope::Function&) + [](Scope::Function&) { yulAssert(false, "Function not removed during desugaring."); } diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 52cd1d23f48a..b5b5eda6ed81 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -41,6 +41,20 @@ using namespace solidity::util; namespace { + +void visitArguments( + AbstractAssembly& _assembly, + FunctionCall const& _call, + function _visitExpression +) +{ + for (auto const& arg: _call.arguments | boost::adaptors::reversed) + _visitExpression(arg); + + _assembly.setSourceLocation(_call.location); +} + + pair createEVMFunction( string const& _name, evmasm::Instruction _instruction @@ -58,12 +72,12 @@ pair createEVMFunction( f.literalArguments.reset(); f.instruction = _instruction; f.generateCode = [_instruction]( - FunctionCall const&, + FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(_instruction); }; @@ -76,7 +90,7 @@ pair createFunction( size_t _returns, SideEffects _sideEffects, vector _literalArguments, - std::function)> _generateCode + std::function)> _generateCode ) { solAssert(_literalArguments.size() == _params || _literalArguments.empty(), ""); @@ -116,7 +130,7 @@ map createBuiltins(langutil::EVMVersion _evmVe FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext& _context, - function + std::function ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); @@ -137,7 +151,7 @@ map createBuiltins(langutil::EVMVersion _evmVe FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext& _context, - std::function + std::function ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); @@ -161,21 +175,58 @@ map createBuiltins(langutil::EVMVersion _evmVe SideEffects{false, false, false, false, true}, {}, []( - FunctionCall const&, + FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(evmasm::Instruction::CODECOPY); } )); + builtins.emplace(createFunction( + "setimmutable", + 2, + 0, + SideEffects{false, false, false, false, true}, + {true, false}, + []( + FunctionCall const& _call, + AbstractAssembly& _assembly, + BuiltinContext&, + std::function _visitExpression + ) { + solAssert(_call.arguments.size() == 2, ""); + + _visitExpression(_call.arguments[1]); + _assembly.setSourceLocation(_call.location); + YulString identifier = std::get(_call.arguments.front()).value; + _assembly.appendImmutableAssignment(identifier.str()); + } + )); + builtins.emplace(createFunction( + "loadimmutable", + 1, + 1, + SideEffects{}, + {true}, + []( + FunctionCall const& _call, + AbstractAssembly& _assembly, + BuiltinContext&, + std::function + ) { + solAssert(_call.arguments.size() == 1, ""); + _assembly.appendImmutable(std::get(_call.arguments.front()).value.str()); + } + )); } return builtins; } } + EVMDialect::EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess): m_objectAccess(_objectAccess), m_evmVersion(_evmVersion), @@ -268,23 +319,23 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA m_functions["popbool"_yulstring].name = "popbool"_yulstring; m_functions["popbool"_yulstring].parameters = {"bool"_yulstring}; m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, {}, []( - FunctionCall const&, - AbstractAssembly&, + FunctionCall const& _call, + AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); })); m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring}; m_functions["bool_to_u256"_yulstring].returns = {"u256"_yulstring}; m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, {}, []( - FunctionCall const&, + FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { // A value larger than 1 causes an invalid instruction. - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); _assembly.appendConstant(2); _assembly.appendInstruction(evmasm::Instruction::DUP2); _assembly.appendInstruction(evmasm::Instruction::LT); diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index 00852fe34b15..68f0b7046fd7 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -49,9 +50,9 @@ struct BuiltinFunctionForEVM: public BuiltinFunction { std::optional instruction; /// Function to generate code for the given function call and append it to the abstract - /// assembly. The fourth parameter is called to visit (and generate code for) the arguments - /// from right to left. - std::function)> generateCode; + /// assembly. The fourth parameter is called to visit (and generate code for) the given + /// argument. + std::function)> generateCode; }; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 8d01c2c5e649..8e26014a9988 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -19,10 +19,14 @@ */ #include + #include #include +#include + + using namespace std; using namespace solidity; using namespace solidity::yul; @@ -142,6 +146,17 @@ AbstractAssembly::SubID NoOutputAssembly::appendData(bytes const&) return 1; } + +void NoOutputAssembly::appendImmutable(std::string const&) +{ + yulAssert(false, "loadimmutable not implemented."); +} + +void NoOutputAssembly::appendImmutableAssignment(std::string const&) +{ + yulAssert(false, "setimmutable not implemented."); +} + NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): EVMDialect(_copyFrom.evmVersion(), _copyFrom.providesObjectAccess()) { @@ -149,9 +164,11 @@ NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): { size_t parameters = fun.second.parameters.size(); size_t returns = fun.second.returns.size(); - fun.second.generateCode = [=](FunctionCall const&, AbstractAssembly& _assembly, BuiltinContext&, std::function _visitArguments) + fun.second.generateCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, std::function _visitExpression) { - _visitArguments(); + for (auto const& arg: _call.arguments | boost::adaptors::reversed) + _visitExpression(arg); + for (size_t i = 0; i < parameters; i++) _assembly.appendInstruction(evmasm::Instruction::POP); diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index d72f9ea66000..7101a30f5a74 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -71,6 +71,9 @@ class NoOutputAssembly: public AbstractAssembly void appendDataSize(SubID _sub) override; SubID appendData(bytes const& _data) override; + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + private: bool m_evm15 = false; ///< if true, switch to evm1.5 mode int m_stackHeight = 0; diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index ad2628695624..249d87a333fa 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -358,13 +358,13 @@ bytes BinaryTransform::operator()(If const& _if) toBytes(Opcode::If) + toBytes(ValueType::Void); - m_labels.push({}); + m_labels.emplace_back(); result += visit(_if.statements); if (_if.elseStatements) result += toBytes(Opcode::Else) + visit(*_if.elseStatements); - m_labels.pop(); + m_labels.pop_back(); result += toBytes(Opcode::End); return result; @@ -374,26 +374,24 @@ bytes BinaryTransform::operator()(Loop const& _loop) { bytes result = toBytes(Opcode::Loop) + toBytes(ValueType::Void); - m_labels.push(_loop.labelName); + m_labels.emplace_back(_loop.labelName); result += visit(_loop.statements); - m_labels.pop(); + m_labels.pop_back(); result += toBytes(Opcode::End); return result; } -bytes BinaryTransform::operator()(Break const&) +bytes BinaryTransform::operator()(Break const& _break) { - yulAssert(false, "br not yet implemented."); - // TODO the index is just the nesting depth. - return {}; + return toBytes(Opcode::Br) + encodeLabelIdx(_break.label.name); } -bytes BinaryTransform::operator()(BreakIf const&) +bytes BinaryTransform::operator()(BreakIf const& _breakIf) { - yulAssert(false, "br_if not yet implemented."); - // TODO the index is just the nesting depth. - return {}; + bytes result = std::visit(*this, *_breakIf.condition); + result += toBytes(Opcode::BrIf) + encodeLabelIdx(_breakIf.label.name); + return result; } bytes BinaryTransform::operator()(Return const&) @@ -403,11 +401,14 @@ bytes BinaryTransform::operator()(Return const&) bytes BinaryTransform::operator()(Block const& _block) { - return + m_labels.emplace_back(_block.labelName); + bytes result = toBytes(Opcode::Block) + toBytes(ValueType::Void) + visit(_block.statements) + toBytes(Opcode::End); + m_labels.pop_back(); + return result; } bytes BinaryTransform::operator()(FunctionDefinition const& _function) @@ -427,9 +428,13 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) for (size_t i = 0; i < _function.locals.size(); ++i) m_locals[_function.locals[i].variableName] = varIdx++; + yulAssert(m_labels.empty(), "Stray labels."); + ret += visit(_function.body); ret += toBytes(Opcode::End); + yulAssert(m_labels.empty(), "Stray labels."); + return prefixSize(std::move(ret)); } @@ -581,6 +586,18 @@ bytes BinaryTransform::visitReversed(vector const& _expressions) return result; } +bytes BinaryTransform::encodeLabelIdx(string const& _label) const +{ + yulAssert(!_label.empty(), "Empty label."); + size_t depth = 0; + for (string const& label: m_labels | boost::adaptors::reversed) + if (label == _label) + return lebEncode(depth); + else + ++depth; + yulAssert(false, "Label not found."); +} + bytes BinaryTransform::encodeName(std::string const& _name) { // UTF-8 is allowed here by the Wasm spec, but since all names here should stem from diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index d4e4375c288b..e11c92bf63bd 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -77,13 +77,15 @@ class BinaryTransform bytes visit(std::vector const& _expressions); bytes visitReversed(std::vector const& _expressions); + bytes encodeLabelIdx(std::string const& _label) const; + static bytes encodeName(std::string const& _name); std::map m_locals; std::map m_globals; std::map m_functions; std::map m_functionTypes; - std::stack m_labels; + std::vector m_labels; std::map> m_subModulePosAndSize; }; diff --git a/libyul/backends/wasm/EVMToEwasmTranslator.cpp b/libyul/backends/wasm/EVMToEwasmTranslator.cpp index dc69d913aa2e..ebcdd961b98c 100644 --- a/libyul/backends/wasm/EVMToEwasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEwasmTranslator.cpp @@ -1232,7 +1232,7 @@ Object EVMToEwasmTranslator::run(Object const& _object) FunctionHoister::run(context, ast); FunctionGrouper::run(context, ast); - MainFunction{}(ast); + MainFunction::run(context, ast); ForLoopConditionIntoBody::run(context, ast); ExpressionSplitter::run(context, ast); WordSizeTransform::run(m_dialect, WasmDialect::instance(), ast, nameDispenser); diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index 3edeb9365f71..2a2499b61697 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -123,7 +123,7 @@ string TextTransform::operator()(wasm::Loop const& _loop) string TextTransform::operator()(wasm::Break const& _break) { - return "(break $" + _break.label.name + ")\n"; + return "(br $" + _break.label.name + ")\n"; } string TextTransform::operator()(wasm::BreakIf const& _break) diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index cb1294d4424e..9c553b380a8c 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -29,9 +29,6 @@ #include -#include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 1640fa1b09cd..1d6b096155fb 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -25,7 +25,6 @@ #include #include -#include using namespace std; using namespace solidity; @@ -60,8 +59,9 @@ void removeEmptyDefaultFromSwitch(Switch& _switchStmt) void removeEmptyCasesFromSwitch(Switch& _switchStmt) { - bool hasDefault = boost::algorithm::any_of( - _switchStmt.cases, + bool hasDefault = std::any_of( + _switchStmt.cases.begin(), + _switchStmt.cases.end(), [](Case const& _case) { return !_case.value; } ); diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp index 8144de49a788..30a5fd5e9e82 100644 --- a/libyul/optimiser/ExpressionSplitter.cpp +++ b/libyul/optimiser/ExpressionSplitter.cpp @@ -31,8 +31,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 32036184af31..a0c80533d139 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -34,8 +34,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/README.md b/libyul/optimiser/README.md index 58cc006b4de5..4bd3d6a36967 100644 --- a/libyul/optimiser/README.md +++ b/libyul/optimiser/README.md @@ -4,6 +4,7 @@ planned state of the optimiser. Table of Contents: +- [Selecting optimisations](#selecting-optimisations) - [Preprocessing](#preprocessing) - [Pseudo-SSA Transformation](#pseudo-ssa-transformation) - [Tools](#tools) @@ -33,6 +34,17 @@ the following transformation steps are the main components: - [Redundant Assign Eliminator](#redundant-assign-eliminator) - [Full Function Inliner](#full-function-inliner) +## Selecting optimisations + +By default the optimiser applies its predefined sequence of optimisation steps to the generated assembly. +You can override this sequence and supply your own using the `--yul-optimizations` option: + +``` bash +solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' +``` + +There's a [table listing available abbreviations in the optimiser docs](/docs/yul.rst#optimization-step-sequence). + ## Preprocessing The preprocessing components perform transformations to get the program diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index 236a27fb08f4..5d1d0557b82b 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -306,7 +306,7 @@ void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEli void AssignmentRemover::operator()(Block& _block) { - boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool { + boost::range::remove_erase_if(_block.statements, [&](Statement const& _statement) -> bool { return holds_alternative(_statement) && m_toRemove.count(&std::get(_statement)); }); diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index 836169701438..0d5da95c1c59 100644 --- a/libyul/optimiser/StructuralSimplifier.cpp +++ b/libyul/optimiser/StructuralSimplifier.cpp @@ -22,7 +22,6 @@ #include #include -#include using namespace std; using namespace solidity; diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 9dc7cedc33cc..a0e0f535dd8b 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -29,8 +29,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; @@ -85,9 +83,10 @@ void UnusedPruner::operator()(Block& _block) // movable or it returns a single value. In the latter case, we // replace `let a := f()` by `pop(f())` (in pure Yul, this will be // `drop(f())`). - if (boost::algorithm::none_of( - varDecl.variables, - [=](TypedName const& _typedName) { return used(_typedName.name); } + if (std::none_of( + varDecl.variables.begin(), + varDecl.variables.end(), + [&](TypedName const& _typedName) { return used(_typedName.name); } )) { if (!varDecl.value) diff --git a/scripts/correct_error_ids.py b/scripts/correct_error_ids.py new file mode 100644 index 000000000000..9fd3547f009d --- /dev/null +++ b/scripts/correct_error_ids.py @@ -0,0 +1,156 @@ +import random +import re +import os +from os import path + +ENCODING = "utf-8" +PATTERN = r"\b\d+_error\b" + + +def read_file(file_name): + content = None + try: + with open(file_name, "r", encoding=ENCODING) as f: + content = f.read() + finally: + if content == None: + print(f"Error reading: {file_name}") + return content + + +def write_file(file_name, content): + with open(file_name, "w", encoding=ENCODING) as f: + f.write(content) + + +def in_comment(source, pos): + slash_slash_pos = source.rfind("//", 0, pos) + lf_pos = source.rfind("\n", 0, pos) + if slash_slash_pos > lf_pos: + return True + slash_star_pos = source.rfind("/*", 0, pos) + star_slash_pos = source.rfind("*/", 0, pos) + return slash_star_pos > star_slash_pos + + +def find_ids_in_file(file_name, ids): + source = read_file(file_name) + for m in re.finditer(PATTERN, source): + if in_comment(source, m.start()): + continue + underscore_pos = m.group(0).index("_") + id = m.group(0)[0:underscore_pos] + if id in ids: + ids[id] += 1 + else: + ids[id] = 1 + + +def get_used_ids(file_names): + used_ids = {} + for file_name in file_names: + find_ids_in_file(file_name, used_ids) + return used_ids + + +def get_id(available_ids, used_ids): + while len(available_ids) > 0: + random.seed(len(available_ids)) + k = random.randrange(len(available_ids)) + id = list(available_ids.keys())[k] + del available_ids[id] + if id not in used_ids: + return id + assert False, "Out of IDs" + + +def fix_ids_in_file(file_name, available_ids, used_ids): + source = read_file(file_name) + + k = 0 + destination = [] + for m in re.finditer(PATTERN, source): + destination.extend(source[k:m.start()]) + + underscore_pos = m.group(0).index("_") + id = m.group(0)[0:underscore_pos] + + # incorrect id or id has a duplicate somewhere + if not in_comment(source, m.start()) and (len(id) != 4 or id[0] == "0" or used_ids[id] > 1): + assert id in used_ids + new_id = get_id(available_ids, used_ids) + used_ids[id] -= 1 + else: + new_id = id + + destination.extend(new_id + "_error") + k = m.end() + + destination.extend(source[k:]) + + destination = ''.join(destination) + if source != destination: + write_file(file_name, destination) + print(f"Fixed file: {file_name}") + + +def fix_ids(used_ids, file_names): + available_ids = {str(id): None for id in range(1000, 10000)} + for file_name in file_names: + fix_ids_in_file(file_name, available_ids, used_ids) + + +def find_source_files(top_dir): + """Builds the list of .h and .cpp files in top_dir directory""" + + source_file_names = [] + dirs = ['libevmasm', 'liblangutil', 'libsolc', 'libsolidity', 'libsolutil', 'libyul', 'solc'] + + for dir in dirs: + for root, _, file_names in os.walk(os.path.join(top_dir, dir), onerror=lambda e: exit(f"Walk error: {e}")): + for file_name in file_names: + _, ext = path.splitext(file_name) + if ext in [".h", ".cpp"]: + source_file_names.append(path.join(root, file_name)) + + return source_file_names + + +def main(): + cwd = os.getcwd() + answer = input( + f"This script checks and corrects *_error literals in .h and .cpp files\n" + f"in {cwd}, recursively.\n\n" + f"Please commit current changes first, and review the results when the script finishes.\n\n" + f"Do you want to start [Y/N]? " + ) + while len(answer) == 0 or answer not in "YNyn": + answer = input("[Y/N]? ") + if answer not in "yY": + return + + source_file_names = find_source_files(cwd) + + used_ids = get_used_ids(source_file_names) + + ok = True + for id in sorted(used_ids): + if len(id) != 4: + print(f"ID {id} length != 4") + ok = False + if id[0] == "0": + print(f"ID {id} starts with zero") + ok = False + if used_ids[id] > 1: + print(f"ID {id} appears {used_ids[id]} times") + ok = False + + if ok: + print("No incorrect IDs found") + else: + fix_ids(used_ids, source_file_names) + print("Fixing compteted") + + +if __name__ == "__main__": + main() diff --git a/scripts/docs.sh b/scripts/docs.sh index 2c08a82bc90e..91f619d89ff7 100755 --- a/scripts/docs.sh +++ b/scripts/docs.sh @@ -28,6 +28,6 @@ set -e cd docs -pip install -r requirements.txt +pip3 install -r requirements.txt sphinx-build -nW -b html -d _build/doctrees . _build/html cd .. diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py index 9dea81aa56e8..768f94801fda 100755 --- a/scripts/isolate_tests.py +++ b/scripts/isolate_tests.py @@ -52,7 +52,7 @@ def extract_docs_cases(path): if inside: extractedLines[-1] += l + '\n' - codeStart = "(pragma solidity|contract.*{|library.*{|interface.*{)" + codeStart = "(// SPDX-License-Identifier:|pragma solidity|contract.*{|library.*{|interface.*{)" # Filter all tests that do not contain Solidity or are intended incorrectly. for lines in extractedLines: diff --git a/scripts/tests.sh b/scripts/tests.sh index c0601a12da0c..00b4a1641742 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -100,7 +100,7 @@ do force_abiv2_flag="" if [[ "$abiv2" == "yes" ]] then - force_abiv2_flag="--abiencoderv2 --optimize-yul" + force_abiv2_flag="--abiencoderv2" fi printTask "--> Running tests using "$optimize" --evm-version "$vm" $force_abiv2_flag..." diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 537b2096baf4..1342ef1f6daa 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -699,7 +699,7 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da string pathName = (p / _fileName).string(); if (fs::exists(pathName) && !m_args.count(g_strOverwrite)) { - serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --overwrite to force)." << endl; + serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --" << g_strOverwrite << " to force)." << endl; m_error = true; return; } @@ -719,10 +719,10 @@ bool CommandLineInterface::parseArguments(int _argc, char** _argv) g_hasOutput = false; // Declare the supported options. - po::options_description desc(R"(solc, the Solidity commandline compiler. + po::options_description desc((R"(solc, the Solidity commandline compiler. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you -are welcome to redistribute it under certain conditions. See 'solc --license' +are welcome to redistribute it under certain conditions. See 'solc --)" + g_strLicense + R"(' for details. Usage: solc [options] [input_file...] @@ -732,9 +732,9 @@ at standard output or in files in the output directory, if specified. Imports are automatically read from the filesystem, but it is also possible to remap paths using the context:prefix=path syntax. Example: -solc --bin -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol +solc --)" + g_argBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol -Allowed options)", +Allowed options)").c_str(), po::options_description::m_default_line_length, po::options_description::m_default_line_length - 23 ); @@ -780,20 +780,27 @@ Allowed options)", ) ( g_argImportAst.c_str(), - "Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " - "Supported Inputs is the output of the --standard-json or the one produced by --combined-json ast,compact-format" + ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " + "Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by " + "--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str() ) ( g_argAssemble.c_str(), - "Switch to assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is assembly." + ("Switch to assembly mode, ignoring all options except " + "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " " + "and assumes input is assembly.").c_str() ) ( g_argYul.c_str(), - "Switch to Yul mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is Yul." + ("Switch to Yul mode, ignoring all options except " + "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " " + "and assumes input is Yul.").c_str() ) ( g_argStrictAssembly.c_str(), - "Switch to strict assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is strict assembly." + ("Switch to strict assembly mode, ignoring all options except " + "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " " + "and assumes input is strict assembly.").c_str() ) ( g_strYulDialect.c_str(), @@ -807,8 +814,8 @@ Allowed options)", ) ( g_argLink.c_str(), - "Switch to linker mode, ignoring all options apart from --libraries " - "and modify binaries in place." + ("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " " + "and modify binaries in place.").c_str() ) ( g_argMetadataHash.c_str(), @@ -835,7 +842,7 @@ Allowed options)", "Set for how many contract runs to optimize. " "Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage." ) - (g_strOptimizeYul.c_str(), "Legacy option, ignored. Use the general --optimize to enable Yul optimizer.") + (g_strOptimizeYul.c_str(), ("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str()) (g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.") ( g_strYulOptimizations.c_str(), @@ -933,7 +940,7 @@ Allowed options)", for (string const& item: boost::split(requests, m_args[g_argCombinedJson].as(), boost::is_any_of(","))) if (!g_combinedJsonArgs.count(item)) { - serr() << "Invalid option to --combined-json: " << item << endl; + serr() << "Invalid option to --" << g_argCombinedJson << ": " << item << endl; return false; } } @@ -1047,7 +1054,7 @@ bool CommandLineInterface::processInput() std::optional versionOption = langutil::EVMVersion::fromString(versionOptionStr); if (!versionOption) { - serr() << "Invalid option for --evm-version: " << versionOptionStr << endl; + serr() << "Invalid option for --" << g_strEVMVersion << ": " << versionOptionStr << endl; return false; } m_evmVersion = *versionOption; @@ -1064,14 +1071,37 @@ bool CommandLineInterface::processInput() bool optimize = m_args.count(g_argOptimize); if (m_args.count(g_strOptimizeYul)) { - serr() << "--optimize-yul is invalid in assembly mode. Use --optimize instead." << endl; + serr() << "--" << g_strOptimizeYul << " is invalid in assembly mode. Use --" << g_argOptimize << " instead." << endl; return false; } if (m_args.count(g_strNoOptimizeYul)) { - serr() << "--no-optimize-yul is invalid in assembly mode. Optimization is disabled by default and can be enabled with --optimize." << endl; + serr() << "--" << g_strNoOptimizeYul << " is invalid in assembly mode. Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl; return false; } + + optional yulOptimiserSteps; + if (m_args.count(g_strYulOptimizations)) + { + if (!optimize) + { + serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl; + return false; + } + + try + { + yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as()); + } + catch (yul::OptimizerException const& _exception) + { + serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl; + return false; + } + + yulOptimiserSteps = m_args[g_strYulOptimizations].as(); + } + if (m_args.count(g_argMachine)) { string machine = m_args[g_argMachine].as(); @@ -1083,7 +1113,7 @@ bool CommandLineInterface::processInput() targetMachine = Machine::Ewasm; else { - serr() << "Invalid option for --machine: " << machine << endl; + serr() << "Invalid option for --" << g_argMachine << ": " << machine << endl; return false; } } @@ -1099,13 +1129,14 @@ bool CommandLineInterface::processInput() inputLanguage = Input::Ewasm; if (targetMachine != Machine::Ewasm) { - serr() << "If you select Ewasm as --yul-dialect, --machine has to be Ewasm as well." << endl; + serr() << "If you select Ewasm as --" << g_strYulDialect << ", "; + serr() << "--" << g_argMachine << " has to be Ewasm as well." << endl; return false; } } else { - serr() << "Invalid option for --yul-dialect: " << dialect << endl; + serr() << "Invalid option for --" << g_strYulDialect << ": " << dialect << endl; return false; } } @@ -1122,7 +1153,7 @@ bool CommandLineInterface::processInput() "Warning: Yul is still experimental. Please use the output with care." << endl; - return assemble(inputLanguage, targetMachine, optimize); + return assemble(inputLanguage, targetMachine, optimize, yulOptimiserSteps); } if (m_args.count(g_argLink)) { @@ -1142,7 +1173,7 @@ bool CommandLineInterface::processInput() m_metadataHash = CompilerStack::MetadataHash::None; else { - serr() << "Invalid option for --metadata-hash: " << hashStr << endl; + serr() << "Invalid option for --" << g_argMetadataHash << ": " << hashStr << endl; return false; } } @@ -1534,18 +1565,21 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _ bool CommandLineInterface::assemble( yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine, - bool _optimize + bool _optimize, + optional _yulOptimiserSteps ) { + solAssert(_optimize || !_yulOptimiserSteps.has_value(), ""); + bool successful = true; map assemblyStacks; for (auto const& src: m_sourceCodes) { - auto& stack = assemblyStacks[src.first] = yul::AssemblyStack( - m_evmVersion, - _language, - _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal() - ); + OptimiserSettings settings = _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal(); + if (_yulOptimiserSteps.has_value()) + settings.yulOptimiserSteps = _yulOptimiserSteps.value(); + + auto& stack = assemblyStacks[src.first] = yul::AssemblyStack(m_evmVersion, _language, settings); try { if (!stack.parseAndAnalyze(src.first, src.second)) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index f6972cf04823..446ea822489d 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -56,7 +56,12 @@ class CommandLineInterface /// @returns the full object with library placeholder hints in hex. static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj); - bool assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine, bool _optimize); + bool assemble( + yul::AssemblyStack::Language _language, + yul::AssemblyStack::Machine _targetMachine, + bool _optimize, + std::optional _yulOptimiserSteps = std::nullopt + ); void outputCompilationResults(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d63d9aec5f81..ff545faf3c08 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -187,7 +187,7 @@ add_executable(soltest ${sources} ${libsolidity_util_sources} ${yul_phaser_sources} ) -target_link_libraries(soltest PRIVATE libsolc yul solidity yulInterpreter evmasm solutil Boost::boost Boost::program_options Boost::unit_test_framework evmc) +target_link_libraries(soltest PRIVATE libsolc yul solidity yulInterpreter evmasm solutil Boost::boost Boost::filesystem Boost::program_options Boost::unit_test_framework evmc) # Special compilation flag for Visual Studio (version 2019 at least affected) diff --git a/test/Common.cpp b/test/Common.cpp index 0ed7c9881854..69bfd21ee447 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -94,7 +94,7 @@ CommonOptions::CommonOptions(std::string _caption): ("evmonepath", po::value(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to evmone library") ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") ("optimize", po::bool_switch(&optimize), "enables optimization") - ("optimize-yul", po::bool_switch(&optimizeYul), "enables Yul optimization") + ("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") ("show-messages", po::bool_switch(&showMessages), "enables message output") ("show-metadata", po::bool_switch(&showMetadata), "enables metadata output"); diff --git a/test/Common.h b/test/Common.h index 513e7154bc21..119050f393b6 100644 --- a/test/Common.h +++ b/test/Common.h @@ -46,7 +46,7 @@ struct CommonOptions: boost::noncopyable boost::filesystem::path evmonePath; boost::filesystem::path testPath; bool optimize = false; - bool optimizeYul = false; + bool enforceViaYul = false; bool disableSMT = false; bool useABIEncoderV2 = false; bool showMessages = false; diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 3c9e6449e942..836d61057273 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -81,12 +81,14 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): m_evmRevision = EVMC_BYZANTIUM; else if (_evmVersion == langutil::EVMVersion::constantinople()) m_evmRevision = EVMC_CONSTANTINOPLE; + else if (_evmVersion == langutil::EVMVersion::petersburg()) + m_evmRevision = EVMC_PETERSBURG; else if (_evmVersion == langutil::EVMVersion::istanbul()) m_evmRevision = EVMC_ISTANBUL; else if (_evmVersion == langutil::EVMVersion::berlin()) - assertThrow(false, Exception, "Berlin is not supported yet."); - else //if (_evmVersion == langutil::EVMVersion::petersburg()) - m_evmRevision = EVMC_PETERSBURG; + m_evmRevision = EVMC_BERLIN; + else + assertThrow(false, Exception, "Unsupported EVM version"); // Mark all precompiled contracts as existing. Existing here means to have a balance (as per EIP-161). // NOTE: keep this in sync with `EVMHost::call` below. @@ -99,17 +101,16 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): evmc::address address{}; address.bytes[19] = precompiledAddress; // 1wei - accounts[address].balance.bytes[31] = 1; + accounts[address].balance = evmc::uint256be{1}; } - // TODO: support short literals in EVMC and use them here - tx_context.block_difficulty = convertToEVMC(u256("200000000")); + tx_context.block_difficulty = evmc::uint256be{200000000}; tx_context.block_gas_limit = 20000000; tx_context.block_coinbase = 0x7878787878787878787878787878787878787878_address; - tx_context.tx_gas_price = convertToEVMC(u256("3000000000")); + tx_context.tx_gas_price = evmc::uint256be{3000000000}; tx_context.tx_origin = 0x9292929292929292929292929292929292929292_address; // Mainnet according to EIP-155 - tx_context.chain_id = convertToEVMC(u256(1)); + tx_context.chain_id = evmc::uint256be{1}; } void EVMHost::selfdestruct(const evmc::address& _addr, const evmc::address& _beneficiary) noexcept diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index 170f5638c6f3..ab11b2e98100 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -49,9 +49,7 @@ ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion): m_showMessages(solidity::test::CommonOptions::get().showMessages), m_evmHost(make_shared(m_evmVersion)) { - if (solidity::test::CommonOptions::get().optimizeYul) - m_optimiserSettings = solidity::frontend::OptimiserSettings::full(); - else if (solidity::test::CommonOptions::get().optimize) + if (solidity::test::CommonOptions::get().optimize) m_optimiserSettings = solidity::frontend::OptimiserSettings::standard(); reset(); diff --git a/test/TestCase.cpp b/test/TestCase.cpp index e0897ae47c47..23f23ac7398b 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -40,6 +40,11 @@ void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; } +void TestCase::printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix) +{ + printSettings(_stream, _linePrefix); +} + bool TestCase::isTestFilename(boost::filesystem::path const& _filename) { string extension = _filename.extension().string(); diff --git a/test/TestCase.h b/test/TestCase.h index 8ec3086fe93b..442b4fd5f16d 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -38,6 +38,7 @@ class TestCase { std::string filename; langutil::EVMVersion evmVersion; + bool enforceCompileViaYul; }; enum class TestResult { Success, Failure, FatalError }; @@ -59,6 +60,8 @@ class TestCase virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const = 0; /// Outputs settings. virtual void printSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false); + /// Outputs updated settings + virtual void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = ""); /// Outputs test expectations to @arg _stream that match the actual results of the test. /// Each line of output is prefixed with @arg _linePrefix. virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const = 0; diff --git a/test/boostTest.cpp b/test/boostTest.cpp index fd7bca132372..eb55ead8995b 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -64,12 +64,13 @@ int registerTests( boost::unit_test::test_suite& _suite, boost::filesystem::path const& _basepath, boost::filesystem::path const& _path, + bool _enforceViaYul, TestCase::TestCaseCreator _testCaseCreator ) { int numTestsAdded = 0; fs::path fullpath = _basepath / _path; - TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion()}; + TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), _enforceViaYul}; if (fs::is_directory(fullpath)) { test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string()); @@ -78,7 +79,12 @@ int registerTests( fs::directory_iterator() )) if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename())) - numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _testCaseCreator); + numTestsAdded += registerTests( + *sub_suite, + _basepath, _path / entry.path().filename(), + _enforceViaYul, + _testCaseCreator + ); _suite.add(sub_suite); } else @@ -164,6 +170,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) master, options.testPath / ts.path, ts.subpath, + options.enforceViaYul, ts.testCaseCreator ) > 0, std::string("no ") + ts.title + " tests found"); } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 077aa5c19e92..07e249492c3e 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -245,7 +245,18 @@ printTask "Running general commandline tests..." stdoutExpectationFile="${tdir}/output.json" args="--standard-json "$(cat ${tdir}/args 2>/dev/null || true) else - inputFile="${tdir}input.sol" + if [[ -e "${tdir}input.yul" && -e "${tdir}input.sol" ]] + then + printError "Ambiguous input. Found both input.sol and input.yul." + exit 1 + fi + + if [ -e "${tdir}input.yul" ] + then + inputFile="${tdir}input.yul" + else + inputFile="${tdir}input.sol" + fi stdin="" stdout="$(cat ${tdir}/output 2>/dev/null || true)" stdoutExpectationFile="${tdir}/output" diff --git a/test/cmdlineTests/abiencoderv2_no_warning/input.sol b/test/cmdlineTests/abiencoderv2_no_warning/input.sol index fef512e55ee2..c2eb120f8304 100644 --- a/test/cmdlineTests/abiencoderv2_no_warning/input.sol +++ b/test/cmdlineTests/abiencoderv2_no_warning/input.sol @@ -1,5 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; pragma experimental ABIEncoderV2; + contract C { struct S { uint x; } function f(S memory) public pure { diff --git a/test/cmdlineTests/evm_to_wasm_break/args b/test/cmdlineTests/evm_to_wasm_break/args new file mode 100644 index 000000000000..099ebdc3a380 --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/args @@ -0,0 +1 @@ +--assemble --optimize --yul-dialect evm --machine ewasm diff --git a/test/cmdlineTests/evm_to_wasm_break/err b/test/cmdlineTests/evm_to_wasm_break/err new file mode 100644 index 000000000000..014a1178fa22 --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/evm_to_wasm_break/input.sol b/test/cmdlineTests/evm_to_wasm_break/input.sol new file mode 100644 index 000000000000..a625eea088e1 --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/input.sol @@ -0,0 +1,8 @@ +{ + let x := calldataload(0) + for { } lt(x, 10) { x := add(x, 1) } { + if eq(x, 2) { break } + if eq(x, 4) { continue } + } + sstore(0, x) +} diff --git a/test/cmdlineTests/evm_to_wasm_break/output b/test/cmdlineTests/evm_to_wasm_break/output new file mode 100644 index 000000000000..3ed2a2dd0e76 --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/output @@ -0,0 +1,551 @@ + +======= evm_to_wasm_break/input.sol (Ewasm) ======= + +Pretty printed source: +object "object" { + code { + { + let x := calldataload(0) + for { } lt(x, 10) { x := add(x, 1) } + { + if eq(x, 2) { break } + if eq(x, 4) { continue } + } + sstore(0, x) + } + } +} + + +========================== + +Translated source: +object "object" { + code { + function main() + { + let _1 := 0 + let x, x_1, x_2, x_3 := calldataload(_1, _1, _1, _1) + let x_4 := x + let x_5 := x_1 + let x_6 := x_2 + let x_7 := x_3 + let _2 := 1 + let _3:i32 := i32.eqz(i32.eqz(i64.eqz(i64.or(i64.or(_1, _1), i64.or(_1, _2))))) + for { } + i32.eqz(_3) + { + let x_8, x_9, x_10, x_11 := add(x_4, x_5, x_6, x_7, _1, _1, _1, _2) + x_4 := x_8 + x_5 := x_9 + x_6 := x_10 + x_7 := x_11 + } + { + let _4, _5, _6, _7 := lt(x_4, x_5, x_6, x_7, _1, _1, _1, 10) + let _8, _9, _10, _11 := iszero(_4, _5, _6, _7) + if i32.eqz(i64.eqz(i64.or(i64.or(_8, _9), i64.or(_10, _11)))) { break } + let _12, _13, _14, _15 := eq(x_4, x_5, x_6, x_7, _1, _1, _1, 2) + if i32.eqz(i64.eqz(i64.or(i64.or(_12, _13), i64.or(_14, _15)))) { break } + let _16, _17, _18, _19 := eq(x_4, x_5, x_6, x_7, _1, _1, _1, 4) + if i32.eqz(i64.eqz(i64.or(i64.or(_16, _17), i64.or(_18, _19)))) { continue } + } + sstore(_1, _1, _1, _1, x_4, x_5, x_6, x_7) + } + function add_carry(x, y, c) -> r, r_c + { + let t := i64.add(x, y) + r := i64.add(t, c) + r_c := i64.extend_i32_u(i32.or(i64.lt_u(t, x), i64.lt_u(r, t))) + } + function add(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 + { + let t := i64.add(x4, y4) + r4 := i64.add(t, 0) + let r3_1, carry := add_carry(x3, y3, i64.extend_i32_u(i32.or(i64.lt_u(t, x4), i64.lt_u(r4, t)))) + r3 := r3_1 + let r2_1, carry_1 := add_carry(x2, y2, carry) + r2 := r2_1 + let r1_1, carry_2 := add_carry(x1, y1, carry_1) + r1 := r1_1 + } + function iszero(x1, x2, x3, x4) -> r1, r2, r3, r4 + { + r4 := i64.extend_i32_u(i64.eqz(i64.or(i64.or(x1, x2), i64.or(x3, x4)))) + } + function eq(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 + { + if i64.eq(x1, y1) + { + if i64.eq(x2, y2) + { + if i64.eq(x3, y3) { if i64.eq(x4, y4) { r4 := 1 } } + } + } + } + function cmp(a, b) -> r:i32 + { + switch i64.lt_u(a, b) + case 1:i32 { r := 0xffffffff:i32 } + default { r := i64.ne(a, b) } + } + function lt(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 + { + let z:i32 := false + switch cmp(x1, y1) + case 0:i32 { + switch cmp(x2, y2) + case 0:i32 { + switch cmp(x3, y3) + case 0:i32 { z := i64.lt_u(x4, y4) } + case 1:i32 { z := 0:i32 } + default { z := 1:i32 } + } + case 1:i32 { z := 0:i32 } + default { z := 1:i32 } + } + case 1:i32 { z := 0:i32 } + default { z := 1:i32 } + z4 := i64.extend_i32_u(z) + } + function calldataload(x1, x2, x3, x4) -> z1, z2, z3, z4 + { + if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { unreachable() } + if i64.ne(0, i64.shr_u(x4, 32)) { unreachable() } + eth.callDataCopy(0:i32, i32.wrap_i64(x4), 32:i32) + let z1_1 := endian_swap(i64.load(0:i32)) + let z2_1 := endian_swap(i64.load(i32.add(0:i32, 8:i32))) + let z3_1 := endian_swap(i64.load(i32.add(0:i32, 16:i32))) + let z4_1 := endian_swap(i64.load(i32.add(0:i32, 24:i32))) + z1 := z1_1 + z2 := z2_1 + z3 := z3_1 + z4 := z4_1 + } + function endian_swap_16(x) -> y + { + y := i64.or(i64.and(i64.shl(x, 8), 0xff00), i64.and(i64.shr_u(x, 8), 0xff)) + } + function endian_swap_32(x) -> y + { + let hi := i64.shl(endian_swap_16(x), 16) + y := i64.or(hi, endian_swap_16(i64.shr_u(x, 16))) + } + function endian_swap(x) -> y + { + let hi := i64.shl(endian_swap_32(x), 32) + y := i64.or(hi, endian_swap_32(i64.shr_u(x, 32))) + } + function mstore_internal(pos:i32, y1, y2, y3, y4) + { + i64.store(pos, endian_swap(y1)) + i64.store(i32.add(pos, 8:i32), endian_swap(y2)) + i64.store(i32.add(pos, 16:i32), endian_swap(y3)) + i64.store(i32.add(pos, 24:i32), endian_swap(y4)) + } + function sstore(x1, x2, x3, x4, y1, y2, y3, y4) + { + mstore_internal(0:i32, x1, x2, x3, x4) + mstore_internal(32:i32, y1, y2, y3, y4) + eth.storageStore(0:i32, 32:i32) + } + } +} + + +Binary representation: +0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020a80090dee02011f7e4200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080b0b20002000200020002005200620072008100e0b2c01037e200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21042004240020030b6f010b7e200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b2011210820092400200a2401200b240220080b2301047e200020018420022003848450ada7ad210720052400200624012007240220040b4601047e2000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b20092400200a2401200b240220080b2a01027e02402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b20020b930101087e4200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b20092400200a2401200b240220080b8c0101087e4200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b210720052400200624012007240220040b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e2000100a421086210220022000421088100a84210120010b1b01027e2000100b422086210220022000422088100b84210120010b3e01007e2000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b2401007e42002000200120022003100d42202004200520062007100d4200a74220a710000b + +Text representation: +(module + (import "ethereum" "storageStore" (func $eth.storageStore (param i32 i32))) + (import "ethereum" "callDataCopy" (func $eth.callDataCopy (param i32 i32 i32))) + (memory $memory (export "memory") 1) + (export "main" (func $main)) + (global $global_ (mut i64) (i64.const 0)) + (global $global__1 (mut i64) (i64.const 0)) + (global $global__2 (mut i64) (i64.const 0)) + +(func $main + (local $_1 i64) + (local $x i64) + (local $x_1 i64) + (local $x_2 i64) + (local $x_3 i64) + (local $x_4 i64) + (local $x_5 i64) + (local $x_6 i64) + (local $x_7 i64) + (local $_2 i64) + (local $_3 i64) + (local $_4 i64) + (local $_5 i64) + (local $_6 i64) + (local $_7 i64) + (local $_8 i64) + (local $_9 i64) + (local $_10 i64) + (local $_11 i64) + (local $_12 i64) + (local $_13 i64) + (local $_14 i64) + (local $_15 i64) + (local $_16 i64) + (local $_17 i64) + (local $_18 i64) + (local $_19 i64) + (local $x_8 i64) + (local $x_9 i64) + (local $x_10 i64) + (local $x_11 i64) + (local.set $_1 (i64.const 0)) + (block + (local.set $x (call $calldataload (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) + (local.set $x_1 (global.get $global_)) + (local.set $x_2 (global.get $global__1)) + (local.set $x_3 (global.get $global__2)) + + ) + (local.set $x_4 (local.get $x)) + (local.set $x_5 (local.get $x_1)) + (local.set $x_6 (local.get $x_2)) + (local.set $x_7 (local.get $x_3)) + (local.set $_2 (i64.const 1)) + (local.set $_3 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_1) (local.get $_1)) (i64.or (local.get $_1) (local.get $_2)))))))))))) + (block $label_ + (loop + (br_if $label_ (i64.eqz (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (local.get $_3)))))) + (block $label__3 + (block + (local.set $_4 (call $lt (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 10))) + (local.set $_5 (global.get $global_)) + (local.set $_6 (global.get $global__1)) + (local.set $_7 (global.get $global__2)) + + ) + (block + (local.set $_8 (call $iszero (local.get $_4) (local.get $_5) (local.get $_6) (local.get $_7))) + (local.set $_9 (global.get $global_)) + (local.set $_10 (global.get $global__1)) + (local.set $_11 (global.get $global__2)) + + ) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_8) (local.get $_9)) (i64.or (local.get $_10) (local.get $_11)))))))) (i64.const 0)) (then + (br $label_) + )) + (block + (local.set $_12 (call $eq (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 2))) + (local.set $_13 (global.get $global_)) + (local.set $_14 (global.get $global__1)) + (local.set $_15 (global.get $global__2)) + + ) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_12) (local.get $_13)) (i64.or (local.get $_14) (local.get $_15)))))))) (i64.const 0)) (then + (br $label_) + )) + (block + (local.set $_16 (call $eq (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 4))) + (local.set $_17 (global.get $global_)) + (local.set $_18 (global.get $global__1)) + (local.set $_19 (global.get $global__2)) + + ) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_16) (local.get $_17)) (i64.or (local.get $_18) (local.get $_19)))))))) (i64.const 0)) (then + (br $label__3) + )) + + ) + (block + (local.set $x_8 (call $add (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))) + (local.set $x_9 (global.get $global_)) + (local.set $x_10 (global.get $global__1)) + (local.set $x_11 (global.get $global__2)) + + ) + (local.set $x_4 (local.get $x_8)) + (local.set $x_5 (local.get $x_9)) + (local.set $x_6 (local.get $x_10)) + (local.set $x_7 (local.get $x_11)) + ) + + ) + (call $sstore (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7)) +) + +(func $add_carry + (param $x i64) + (param $y i64) + (param $c i64) + (result i64) + (local $r i64) + (local $r_c i64) + (local $t i64) + (local.set $t (i64.add (local.get $x) (local.get $y))) + (local.set $r (i64.add (local.get $t) (local.get $c))) + (local.set $r_c (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $t))))))))) + (global.set $global_ (local.get $r_c)) + (local.get $r) +) + +(func $add + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (result i64) + (local $r1 i64) + (local $r2 i64) + (local $r3 i64) + (local $r4 i64) + (local $t i64) + (local $r3_1 i64) + (local $carry i64) + (local $r2_1 i64) + (local $carry_1 i64) + (local $r1_1 i64) + (local $carry_2 i64) + (local.set $t (i64.add (local.get $x4) (local.get $y4))) + (local.set $r4 (i64.add (local.get $t) (i64.const 0))) + (block + (local.set $r3_1 (call $add_carry (local.get $x3) (local.get $y3) (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x4)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r4) (local.get $t)))))))))) + (local.set $carry (global.get $global_)) + + ) + (local.set $r3 (local.get $r3_1)) + (block + (local.set $r2_1 (call $add_carry (local.get $x2) (local.get $y2) (local.get $carry))) + (local.set $carry_1 (global.get $global_)) + + ) + (local.set $r2 (local.get $r2_1)) + (block + (local.set $r1_1 (call $add_carry (local.get $x1) (local.get $y1) (local.get $carry_1))) + (local.set $carry_2 (global.get $global_)) + + ) + (local.set $r1 (local.get $r1_1)) + (global.set $global_ (local.get $r2)) + (global.set $global__1 (local.get $r3)) + (global.set $global__2 (local.get $r4)) + (local.get $r1) +) + +(func $iszero + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (result i64) + (local $r1 i64) + (local $r2 i64) + (local $r3 i64) + (local $r4 i64) + (local.set $r4 (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $x1) (local.get $x2)) (i64.or (local.get $x3) (local.get $x4)))))))) + (global.set $global_ (local.get $r2)) + (global.set $global__1 (local.get $r3)) + (global.set $global__2 (local.get $r4)) + (local.get $r1) +) + +(func $eq + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (result i64) + (local $r1 i64) + (local $r2 i64) + (local $r3 i64) + (local $r4 i64) + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x1) (local.get $y1))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x2) (local.get $y2))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x3) (local.get $y3))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x4) (local.get $y4))) (i64.const 0)) (then + (local.set $r4 (i64.const 1)) + )) + )) + )) + )) + (global.set $global_ (local.get $r2)) + (global.set $global__1 (local.get $r3)) + (global.set $global__2 (local.get $r4)) + (local.get $r1) +) + +(func $cmp + (param $a i64) + (param $b i64) + (result i64) + (local $r i64) + (local $condition i64) + (block + (local.set $condition (i64.extend_i32_u (i64.lt_u (local.get $a) (local.get $b)))) + (if (i64.eq (local.get $condition) (i64.const 1)) (then + (local.set $r (i64.const 4294967295)) + )(else + (local.set $r (i64.extend_i32_u (i64.ne (local.get $a) (local.get $b)))) + )) + + ) + (local.get $r) +) + +(func $lt + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (result i64) + (local $z1 i64) + (local $z2 i64) + (local $z3 i64) + (local $z4 i64) + (local $z i64) + (local $condition_4 i64) + (local $condition_5 i64) + (local $condition_6 i64) + (local.set $z (i64.const 0)) + (block + (local.set $condition_4 (call $cmp (local.get $x1) (local.get $y1))) + (if (i64.eq (local.get $condition_4) (i64.const 0)) (then + (block + (local.set $condition_5 (call $cmp (local.get $x2) (local.get $y2))) + (if (i64.eq (local.get $condition_5) (i64.const 0)) (then + (block + (local.set $condition_6 (call $cmp (local.get $x3) (local.get $y3))) + (if (i64.eq (local.get $condition_6) (i64.const 0)) (then + (local.set $z (i64.extend_i32_u (i64.lt_u (local.get $x4) (local.get $y4)))) + )(else + (if (i64.eq (local.get $condition_6) (i64.const 1)) (then + (local.set $z (i64.const 0)) + )(else + (local.set $z (i64.const 1)) + )) + )) + + ) + )(else + (if (i64.eq (local.get $condition_5) (i64.const 1)) (then + (local.set $z (i64.const 0)) + )(else + (local.set $z (i64.const 1)) + )) + )) + + ) + )(else + (if (i64.eq (local.get $condition_4) (i64.const 1)) (then + (local.set $z (i64.const 0)) + )(else + (local.set $z (i64.const 1)) + )) + )) + + ) + (local.set $z4 (i64.extend_i32_u (i32.wrap_i64 (local.get $z)))) + (global.set $global_ (local.get $z2)) + (global.set $global__1 (local.get $z3)) + (global.set $global__2 (local.get $z4)) + (local.get $z1) +) + +(func $calldataload + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (result i64) + (local $z1 i64) + (local $z2 i64) + (local $z3 i64) + (local $z4 i64) + (local $z1_1 i64) + (local $z2_1 i64) + (local $z3_1 i64) + (local $z4_1 i64) + (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then + (unreachable))) + (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then + (unreachable))) + (call $eth.callDataCopy (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.extend_i32_u (i32.wrap_i64 (local.get $x4)))) (i32.wrap_i64 (i64.const 32))) + (local.set $z1_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0))))) + (local.set $z2_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8)))))))) + (local.set $z3_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16)))))))) + (local.set $z4_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24)))))))) + (local.set $z1 (local.get $z1_1)) + (local.set $z2 (local.get $z2_1)) + (local.set $z3 (local.get $z3_1)) + (local.set $z4 (local.get $z4_1)) + (global.set $global_ (local.get $z2)) + (global.set $global__1 (local.get $z3)) + (global.set $global__2 (local.get $z4)) + (local.get $z1) +) + +(func $endian_swap_16 + (param $x i64) + (result i64) + (local $y i64) + (local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255)))) + (local.get $y) +) + +(func $endian_swap_32 + (param $x i64) + (result i64) + (local $y i64) + (local $hi i64) + (local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16))) + (local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16))))) + (local.get $y) +) + +(func $endian_swap + (param $x i64) + (result i64) + (local $y i64) + (local $hi i64) + (local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) + (local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32))))) + (local.get $y) +) + +(func $mstore_internal + (param $pos i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1))) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 8))))) (call $endian_swap (local.get $y2))) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 16))))) (call $endian_swap (local.get $y3))) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4))) +) + +(func $sstore + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (call $mstore_internal (i64.const 0) (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) + (call $mstore_internal (i64.const 32) (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)) + (call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32))) +) + +) diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol index 69f553304338..160c4cd1dee2 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; contract C { diff --git a/test/cmdlineTests/ir_compiler_subobjects/err b/test/cmdlineTests/ir_compiler_subobjects/err index a28ad19665ba..d4394af57256 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/err +++ b/test/cmdlineTests/ir_compiler_subobjects/err @@ -1,5 +1,5 @@ Warning: Unused local variable. - --> ir_compiler_subobjects/input.sol:6:9: + --> ir_compiler_subobjects/input.sol:7:9: | -6 | C c = new C(); +7 | C c = new C(); | ^^^ diff --git a/test/cmdlineTests/ir_compiler_subobjects/input.sol b/test/cmdlineTests/ir_compiler_subobjects/input.sol index e0fdbbc136fb..13f9f3c60efd 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/input.sol +++ b/test/cmdlineTests/ir_compiler_subobjects/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; contract C {} diff --git a/test/cmdlineTests/message_format/input.sol b/test/cmdlineTests/message_format/input.sol index 6f854f96af69..cbb51c9d6203 100644 --- a/test/cmdlineTests/message_format/input.sol +++ b/test/cmdlineTests/message_format/input.sol @@ -1,5 +1,5 @@ // checks that error messages around power-or-10 lines are formatted correctly - +// SPDX-License-Identifier: GPL-3.0 diff --git a/test/cmdlineTests/optimizer_user_yul/input.sol b/test/cmdlineTests/optimizer_user_yul/input.sol index 74dc84cbd831..e61b132e493d 100644 --- a/test/cmdlineTests/optimizer_user_yul/input.sol +++ b/test/cmdlineTests/optimizer_user_yul/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/optimizer_user_yul/output b/test/cmdlineTests/optimizer_user_yul/output index b95f2e0fa943..a160c37c4e45 100644 --- a/test/cmdlineTests/optimizer_user_yul/output +++ b/test/cmdlineTests/optimizer_user_yul/output @@ -1,69 +1,69 @@ ======= optimizer_user_yul/input.sol:C ======= EVM assembly: - /* "optimizer_user_yul/input.sol":24:489 contract C... */ + /* "optimizer_user_yul/input.sol":60:525 contract C... */ mstore(0x40, 0x80) - /* "optimizer_user_yul/input.sol":72:77 int a */ + /* "optimizer_user_yul/input.sol":108:113 int a */ 0x00 - /* "optimizer_user_yul/input.sol":38:487 constructor() public payable... */ + /* "optimizer_user_yul/input.sol":188:197 let x,y,z */ dup1 0x00 dup1 - /* "optimizer_user_yul/input.sol":176:177 1 */ + /* "optimizer_user_yul/input.sol":212:213 1 */ 0x01 - /* "optimizer_user_yul/input.sol":173:174 0 */ + /* "optimizer_user_yul/input.sol":209:210 0 */ 0x00 - /* "optimizer_user_yul/input.sol":166:178 sstore(0, 1) */ + /* "optimizer_user_yul/input.sol":202:214 sstore(0, 1) */ sstore - /* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */ + /* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */ tag_3: - /* "optimizer_user_yul/input.sol":197:198 4 */ + /* "optimizer_user_yul/input.sol":233:234 4 */ 0x04 - /* "optimizer_user_yul/input.sol":191:199 sload(4) */ + /* "optimizer_user_yul/input.sol":227:235 sload(4) */ sload - /* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */ + /* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */ iszero tag_5 jumpi pop - /* "optimizer_user_yul/input.sol":215:224 exp(x, y) */ + /* "optimizer_user_yul/input.sol":251:260 exp(x, y) */ dup1 dup3 exp - /* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */ + /* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */ jump(tag_3) tag_5: - /* "optimizer_user_yul/input.sol":187:190 { } */ + /* "optimizer_user_yul/input.sol":223:226 { } */ pop pop pop - /* "optimizer_user_yul/input.sol":239:240 2 */ + /* "optimizer_user_yul/input.sol":275:276 2 */ 0x02 - /* "optimizer_user_yul/input.sol":234:240 a := 2 */ + /* "optimizer_user_yul/input.sol":270:276 a := 2 */ swap1 pop - /* "optimizer_user_yul/input.sol":340:341 3 */ + /* "optimizer_user_yul/input.sol":376:377 3 */ 0x03 - /* "optimizer_user_yul/input.sol":337:338 2 */ + /* "optimizer_user_yul/input.sol":373:374 2 */ 0x02 - /* "optimizer_user_yul/input.sol":330:342 sstore(2, 3) */ + /* "optimizer_user_yul/input.sol":366:378 sstore(2, 3) */ sstore - /* "optimizer_user_yul/input.sol":347:480 for { } sload(5) { } {... */ + /* "optimizer_user_yul/input.sol":383:516 for { } sload(5) { } {... */ tag_6: - /* "optimizer_user_yul/input.sol":361:362 5 */ + /* "optimizer_user_yul/input.sol":397:398 5 */ 0x05 - /* "optimizer_user_yul/input.sol":355:363 sload(5) */ + /* "optimizer_user_yul/input.sol":391:399 sload(5) */ sload tag_9 jumpi jump(tag_8) tag_9: - /* "optimizer_user_yul/input.sol":347:480 for { } sload(5) { } {... */ + /* "optimizer_user_yul/input.sol":383:516 for { } sload(5) { } {... */ jump(tag_6) tag_8: - /* "optimizer_user_yul/input.sol":311:484 {... */ + /* "optimizer_user_yul/input.sol":347:520 {... */ pop - /* "optimizer_user_yul/input.sol":24:489 contract C... */ + /* "optimizer_user_yul/input.sol":60:525 contract C... */ dataSize(sub_0) dup1 dataOffset(sub_0) @@ -74,7 +74,7 @@ tag_8: stop sub_0: assembly { - /* "optimizer_user_yul/input.sol":24:489 contract C... */ + /* "optimizer_user_yul/input.sol":60:525 contract C... */ mstore(0x40, 0x80) /* "--CODEGEN--":12:13 */ 0x00 diff --git a/test/cmdlineTests/output_selection_all_A1/input.json b/test/cmdlineTests/output_selection_all_A1/input.json index 339077d0bcb2..a7a84163de96 100644 --- a/test/cmdlineTests/output_selection_all_A1/input.json +++ b/test/cmdlineTests/output_selection_all_A1/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_A1/output.json b/test/cmdlineTests/output_selection_all_A1/output.json index e87df29955ce..074b2062b216 100644 --- a/test/cmdlineTests/output_selection_all_A1/output.json +++ b/test/cmdlineTests/output_selection_all_A1/output.json @@ -1,6 +1,6 @@ {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_A2/input.json b/test/cmdlineTests/output_selection_all_A2/input.json index 4a29266ad71c..3107a5e4c783 100644 --- a/test/cmdlineTests/output_selection_all_A2/input.json +++ b/test/cmdlineTests/output_selection_all_A2/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_A2/output.json b/test/cmdlineTests/output_selection_all_A2/output.json index 7601952b6c58..aa2ca9d0e121 100644 --- a/test/cmdlineTests/output_selection_all_A2/output.json +++ b/test/cmdlineTests/output_selection_all_A2/output.json @@ -1,6 +1,6 @@ {"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_blank/input.json b/test/cmdlineTests/output_selection_all_blank/input.json index 08c2946c664c..85bc114b3317 100644 --- a/test/cmdlineTests/output_selection_all_blank/input.json +++ b/test/cmdlineTests/output_selection_all_blank/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_blank/output.json b/test/cmdlineTests/output_selection_all_blank/output.json index 81c98e790982..e0872ca8cbdf 100644 --- a/test/cmdlineTests/output_selection_all_blank/output.json +++ b/test/cmdlineTests/output_selection_all_blank/output.json @@ -1,6 +1,6 @@ {"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_star/input.json b/test/cmdlineTests/output_selection_all_star/input.json index 5d079abd3d8b..450286311a48 100644 --- a/test/cmdlineTests/output_selection_all_star/input.json +++ b/test/cmdlineTests/output_selection_all_star/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_star/output.json b/test/cmdlineTests/output_selection_all_star/output.json index 0a8071aaf15d..8997ed8e2dc6 100644 --- a/test/cmdlineTests/output_selection_all_star/output.json +++ b/test/cmdlineTests/output_selection_all_star/output.json @@ -1,6 +1,6 @@ {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_A1/input.json b/test/cmdlineTests/output_selection_single_A1/input.json index 5f11ce6da765..2ea69a594f40 100644 --- a/test/cmdlineTests/output_selection_single_A1/input.json +++ b/test/cmdlineTests/output_selection_single_A1/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_single_B1/input.json b/test/cmdlineTests/output_selection_single_B1/input.json index 6adcd139e45e..f25a1b57dce5 100644 --- a/test/cmdlineTests/output_selection_single_B1/input.json +++ b/test/cmdlineTests/output_selection_single_B1/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_single_B1/output.json b/test/cmdlineTests/output_selection_single_B1/output.json index fafe87ebdfd9..c9c929b971f7 100644 --- a/test/cmdlineTests/output_selection_single_B1/output.json +++ b/test/cmdlineTests/output_selection_single_B1/output.json @@ -1,5 +1,5 @@ {"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_all/input.json b/test/cmdlineTests/output_selection_single_all/input.json index 1dddfe771c2a..a4137b063cdf 100644 --- a/test/cmdlineTests/output_selection_single_all/input.json +++ b/test/cmdlineTests/output_selection_single_all/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/recovery_ast_constructor/err b/test/cmdlineTests/recovery_ast_constructor/err index 81c911386d01..ecff59f7a73c 100644 --- a/test/cmdlineTests/recovery_ast_constructor/err +++ b/test/cmdlineTests/recovery_ast_constructor/err @@ -1,13 +1,13 @@ Error: Expected primary expression. - --> recovery_ast_constructor/input.sol:5:27: + --> recovery_ast_constructor/input.sol:6:27: | -5 | balances[tx.origin] = ; // missing RHS. +6 | balances[tx.origin] = ; // missing RHS. | ^ Warning: Recovered in Statement at ';'. - --> recovery_ast_constructor/input.sol:5:27: + --> recovery_ast_constructor/input.sol:6:27: | -5 | balances[tx.origin] = ; // missing RHS. +6 | balances[tx.origin] = ; // missing RHS. | ^ diff --git a/test/cmdlineTests/recovery_ast_constructor/input.sol b/test/cmdlineTests/recovery_ast_constructor/input.sol index a6b55ab7faa7..9035590d9c44 100644 --- a/test/cmdlineTests/recovery_ast_constructor/input.sol +++ b/test/cmdlineTests/recovery_ast_constructor/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0.0; contract Error1 { diff --git a/test/cmdlineTests/recovery_ast_constructor/output b/test/cmdlineTests/recovery_ast_constructor/output index f2cc2ccf871c..06d7bb95ced8 100644 --- a/test/cmdlineTests/recovery_ast_constructor/output +++ b/test/cmdlineTests/recovery_ast_constructor/output @@ -12,7 +12,8 @@ JSON AST: [ 18 ] - } + }, + "license": "GPL-3.0" }, "children": [ @@ -29,7 +30,7 @@ JSON AST: }, "id": 1, "name": "PragmaDirective", - "src": "0:24:0" + "src": "36:24:0" }, { "attributes": @@ -86,7 +87,7 @@ JSON AST: "children": [], "id": 2, "name": "ParameterList", - "src": "57:2:0" + "src": "93:2:0" }, { "attributes": @@ -99,7 +100,7 @@ JSON AST: "children": [], "id": 3, "name": "ParameterList", - "src": "67:0:0" + "src": "103:0:0" }, { "attributes": @@ -112,12 +113,12 @@ JSON AST: "children": [], "id": 8, "name": "Block", - "src": "67:49:0" + "src": "103:49:0" } ], "id": 9, "name": "FunctionDefinition", - "src": "46:70:0" + "src": "82:70:0" }, { "attributes": @@ -151,7 +152,7 @@ JSON AST: "children": [], "id": 10, "name": "ParameterList", - "src": "382:2:0" + "src": "418:2:0" }, { "children": @@ -180,17 +181,17 @@ JSON AST: }, "id": 11, "name": "ElementaryTypeName", - "src": "405:4:0" + "src": "441:4:0" } ], "id": 12, "name": "VariableDeclaration", - "src": "405:4:0" + "src": "441:4:0" } ], "id": 13, "name": "ParameterList", - "src": "404:6:0" + "src": "440:6:0" }, { "children": @@ -218,30 +219,30 @@ JSON AST: }, "id": 14, "name": "Literal", - "src": "424:1:0" + "src": "460:1:0" } ], "id": 15, "name": "Return", - "src": "417:8:0" + "src": "453:8:0" } ], "id": 16, "name": "Block", - "src": "411:19:0" + "src": "447:19:0" } ], "id": 17, "name": "FunctionDefinition", - "src": "369:61:0" + "src": "405:61:0" } ], "id": 18, "name": "ContractDefinition", - "src": "26:406:0" + "src": "62:406:0" } ], "id": 19, "name": "SourceUnit", - "src": "0:433:0" + "src": "36:433:0" } diff --git a/test/cmdlineTests/recovery_ast_empty_contract/err b/test/cmdlineTests/recovery_ast_empty_contract/err index 3de346d51ef6..588067877fc1 100644 --- a/test/cmdlineTests/recovery_ast_empty_contract/err +++ b/test/cmdlineTests/recovery_ast_empty_contract/err @@ -1,7 +1,7 @@ Error: Expected pragma, import directive or contract/interface/library/struct/enum definition. - --> recovery_ast_empty_contract/input.sol:2:1: + --> recovery_ast_empty_contract/input.sol:3:1: | -2 | c +3 | c | ^ diff --git a/test/cmdlineTests/recovery_ast_empty_contract/input.sol b/test/cmdlineTests/recovery_ast_empty_contract/input.sol index c54a818bfb25..bdc83a2c9013 100644 --- a/test/cmdlineTests/recovery_ast_empty_contract/input.sol +++ b/test/cmdlineTests/recovery_ast_empty_contract/input.sol @@ -1,2 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 pragma 0.5.11; c \ No newline at end of file diff --git a/test/cmdlineTests/recovery_standard_json/input.json b/test/cmdlineTests/recovery_standard_json/input.json index bc0d019d20f9..9c8b15066877 100644 --- a/test/cmdlineTests/recovery_standard_json/input.json +++ b/test/cmdlineTests/recovery_standard_json/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }" } }, "settings": diff --git a/test/cmdlineTests/recovery_standard_json/output.json b/test/cmdlineTests/recovery_standard_json/output.json index 1f2ab6eb623e..18a3b97ce2fd 100644 --- a/test/cmdlineTests/recovery_standard_json/output.json +++ b/test/cmdlineTests/recovery_standard_json/output.json @@ -1,7 +1,7 @@ -{"errors":[{"component":"general","formattedMessage":"A:1:58: ParserError: Expected type name +{"errors":[{"component":"general","formattedMessage":"A:2:58: ParserError: Expected type name pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ -","message":"Expected type name","severity":"error","sourceLocation":{"end":58,"file":"A","start":57},"type":"ParserError"},{"component":"general","formattedMessage":"A:1:84: Warning: Recovered in ContractDefinition at '}'. +","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ -","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":84,"file":"A","start":83},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"0:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"23:35:0"}],"src":"0:84:0"},"id":0}}} +","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}} diff --git a/test/cmdlineTests/require_overload/err b/test/cmdlineTests/require_overload/err index 83f027608679..4c33672d4a27 100644 --- a/test/cmdlineTests/require_overload/err +++ b/test/cmdlineTests/require_overload/err @@ -1,7 +1,7 @@ Error: No matching declaration found after argument-dependent lookup. - --> require_overload/input.sol:4:9: + --> require_overload/input.sol:5:9: | -4 | require(this); +5 | require(this); | ^^^^^^^ Note: Candidate: function require(bool) Note: Candidate: function require(bool, string memory) diff --git a/test/cmdlineTests/require_overload/input.sol b/test/cmdlineTests/require_overload/input.sol index 6d48ac24a7e1..b927c043ccae 100644 --- a/test/cmdlineTests/require_overload/input.sol +++ b/test/cmdlineTests/require_overload/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C { function f() public pure { diff --git a/test/cmdlineTests/standard_default_success/input.json b/test/cmdlineTests/standard_default_success/input.json index 826253b859f2..47a36711397b 100644 --- a/test/cmdlineTests/standard_default_success/input.json +++ b/test/cmdlineTests/standard_default_success/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_eWasm_requested/input.json b/test/cmdlineTests/standard_eWasm_requested/input.json index 9476629e14d4..25cc1705dfd9 100644 --- a/test/cmdlineTests/standard_eWasm_requested/input.json +++ b/test/cmdlineTests/standard_eWasm_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { }" } }, "settings": diff --git a/test/cmdlineTests/standard_empty_file_name/input.json b/test/cmdlineTests/standard_empty_file_name/input.json index 95c2cdd307aa..209f994c5c41 100644 --- a/test/cmdlineTests/standard_empty_file_name/input.json +++ b/test/cmdlineTests/standard_empty_file_name/input.json @@ -4,7 +4,7 @@ { "": { - "content": "pragma solidity >=0.0; import {A} from \".\";" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; import {A} from \".\";" } } } diff --git a/test/cmdlineTests/standard_empty_file_name/output.json b/test/cmdlineTests/standard_empty_file_name/output.json index b31ceb152a8d..d1ab4c870f36 100644 --- a/test/cmdlineTests/standard_empty_file_name/output.json +++ b/test/cmdlineTests/standard_empty_file_name/output.json @@ -1,4 +1,4 @@ -{"errors":[{"component":"general","formattedMessage":":1:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). +{"errors":[{"component":"general","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). pragma solidity >=0.0; import {A} from \".\"; ^------------------^ ","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}} diff --git a/test/cmdlineTests/standard_immutable_references/input.json b/test/cmdlineTests/standard_immutable_references/input.json index 15213be74eb1..d81365c8adc2 100644 --- a/test/cmdlineTests/standard_immutable_references/input.json +++ b/test/cmdlineTests/standard_immutable_references/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A { uint256 immutable x = 1; function f() public view returns (uint256) { return x; } }" + "content": "// SPDX-License-Identifier: GPL-3.0\ncontract A { uint256 immutable x = 1; function f() public view returns (uint256) { return x; } }" } }, "settings": { diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json index 2788a8e732f8..edb5d74d0255 100644 --- a/test/cmdlineTests/standard_immutable_references/output.json +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"0:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;0:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;38:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;72:7;90:1;83:8;;38:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;36:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;74:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_irOptimized_requested/input.json b/test/cmdlineTests/standard_irOptimized_requested/input.json index 96ea078bdcf7..09aa37baeb3b 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/input.json +++ b/test/cmdlineTests/standard_irOptimized_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_ir_requested/input.json b/test/cmdlineTests/standard_ir_requested/input.json index 37404ddba9ef..cc0a91df97af 100644 --- a/test/cmdlineTests/standard_ir_requested/input.json +++ b/test/cmdlineTests/standard_ir_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index bf9b20ed82a3..f63075090caa 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -14,6 +14,7 @@ object \"C_6\" { constructor_C_6() codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) + return(0, datasize(\"C_6_deployed\")) function constructor_C_6() { @@ -64,7 +65,7 @@ object \"C_6\" { mstore(64, newFreePtr) } - function fun_f_5() { + function fun_f_5() { } diff --git a/test/cmdlineTests/standard_method_identifiers_requested/input.json b/test/cmdlineTests/standard_method_identifiers_requested/input.json index 79a3c75d27db..c7a770fb4411 100644 --- a/test/cmdlineTests/standard_method_identifiers_requested/input.json +++ b/test/cmdlineTests/standard_method_identifiers_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json b/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json index 8627a282a806..459f991b4832 100644 --- a/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json +++ b/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_only_ast_requested/input.json b/test/cmdlineTests/standard_only_ast_requested/input.json index 7abd6da5fd37..56409a9a1fae 100644 --- a/test/cmdlineTests/standard_only_ast_requested/input.json +++ b/test/cmdlineTests/standard_only_ast_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_only_ast_requested/output.json b/test/cmdlineTests/standard_only_ast_requested/output.json index 6ba921abf0ea..c1ffe58929e3 100644 --- a/test/cmdlineTests/standard_only_ast_requested/output.json +++ b/test/cmdlineTests/standard_only_ast_requested/output.json @@ -1 +1 @@ -{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"0:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"61:2:0","statements":[]},"documentation":null,"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nodeType":"FunctionDefinition","overrides":null,"parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"46:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"61:0:0"},"scope":6,"src":"36:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"23:42:0"}],"src":"0:65:0"},"id":0}}} +{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"97:2:0","statements":[]},"documentation":null,"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nodeType":"FunctionDefinition","overrides":null,"parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"82:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"97:0:0"},"scope":6,"src":"72:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"59:42:0"}],"src":"36:65:0"},"id":0}}} diff --git a/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json b/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json index f0ce43e37dfd..5e90f6d9868e 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json +++ b/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_invalid_details/input.json b/test/cmdlineTests/standard_optimizer_invalid_details/input.json index 850f6f77c78a..eecfbd5e5a1b 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_details/input.json +++ b/test/cmdlineTests/standard_optimizer_invalid_details/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_no_yul/input.json b/test/cmdlineTests/standard_optimizer_no_yul/input.json index 23f14b48815e..a42299fbee16 100644 --- a/test/cmdlineTests/standard_optimizer_no_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_no_yul/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yul/input.json b/test/cmdlineTests/standard_optimizer_yul/input.json index 3cafae03ad24..5e81a609163e 100644 --- a/test/cmdlineTests/standard_optimizer_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_yul/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails/input.json b/test/cmdlineTests/standard_optimizer_yulDetails/input.json index 5203e64bf12d..842468bca80a 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json index 18d3852dbf45..2581aeb718c0 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json index 00919a864d77..0dcdab6c2818 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": 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 25b3c4bb486d..42756676423d 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json index c322913d9fd6..851e132e8ca4 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json index c02aa6bb32a5..11bc9ca624ec 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json index d6e1e0dc7b1f..79c52e6ddf2b 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json index 056aee91bfd0..cac3c068bee1 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_secondary_source_location/input.json b/test/cmdlineTests/standard_secondary_source_location/input.json index f08069d9f88b..0cd6a6126492 100644 --- a/test/cmdlineTests/standard_secondary_source_location/input.json +++ b/test/cmdlineTests/standard_secondary_source_location/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}" } } } diff --git a/test/cmdlineTests/standard_secondary_source_location/output.json b/test/cmdlineTests/standard_secondary_source_location/output.json index 0330135e2869..d9f56b80d688 100644 --- a/test/cmdlineTests/standard_secondary_source_location/output.json +++ b/test/cmdlineTests/standard_secondary_source_location/output.json @@ -1,10 +1,10 @@ -{"errors":[{"component":"general","formattedMessage":"A:1:112: DeclarationError: Base constructor arguments given twice. +{"errors":[{"component":"general","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^-------------------^ -A:1:81: First constructor call is here: +A:2:81: First constructor call is here: pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^--^ -A:1:104: Second constructor call is here: +A:2:104: Second constructor call is here: pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^--^ -","message":"Base constructor arguments given twice.","secondarySourceLocations":[{"end":84,"file":"A","message":"First constructor call is here:","start":80},{"end":107,"file":"A","message":"Second constructor call is here:","start":103}],"severity":"error","sourceLocation":{"end":132,"file":"A","start":111},"type":"DeclarationError"}],"sources":{}} +","message":"Base constructor arguments given twice.","secondarySourceLocations":[{"end":119,"file":"A","message":"First constructor call is here:","start":115},{"end":142,"file":"A","message":"Second constructor call is here:","start":138}],"severity":"error","sourceLocation":{"end":167,"file":"A","start":146},"type":"DeclarationError"}],"sources":{}} diff --git a/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json b/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json index 51dbce41a53d..0843460ed2e2 100644 --- a/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json +++ b/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "auxiliaryInput": diff --git a/test/cmdlineTests/standard_wrong_key_metadata/input.json b/test/cmdlineTests/standard_wrong_key_metadata/input.json index 490e489a24e1..a52d45004b57 100644 --- a/test/cmdlineTests/standard_wrong_key_metadata/input.json +++ b/test/cmdlineTests/standard_wrong_key_metadata/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_key_optimizer/input.json b/test/cmdlineTests/standard_wrong_key_optimizer/input.json index c28c3a92dcc7..945c1e3460ee 100644 --- a/test/cmdlineTests/standard_wrong_key_optimizer/input.json +++ b/test/cmdlineTests/standard_wrong_key_optimizer/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_key_root/input.json b/test/cmdlineTests/standard_wrong_key_root/input.json index 4689c50c0fbe..2fb1a656b696 100644 --- a/test/cmdlineTests/standard_wrong_key_root/input.json +++ b/test/cmdlineTests/standard_wrong_key_root/input.json @@ -5,7 +5,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_wrong_key_settings/input.json b/test/cmdlineTests/standard_wrong_key_settings/input.json index d7809b1c8064..8f0e1d06b96e 100644 --- a/test/cmdlineTests/standard_wrong_key_settings/input.json +++ b/test/cmdlineTests/standard_wrong_key_settings/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_key_source/input.json b/test/cmdlineTests/standard_wrong_key_source/input.json index d8a8aa16f03b..f4b0f560aae5 100644 --- a/test/cmdlineTests/standard_wrong_key_source/input.json +++ b/test/cmdlineTests/standard_wrong_key_source/input.json @@ -5,7 +5,7 @@ "A": { "key1": "test", - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json index 8d2c75931a38..895aa80ee014 100644 --- a/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "auxiliaryInput": [1, 2, 3] diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json index 9175050fdf61..46090f7e3a30 100644 --- a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json index aa7d451b16bb..96ca950b1596 100644 --- a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_metadata/input.json b/test/cmdlineTests/standard_wrong_type_metadata/input.json index d4dd06a1f6cc..0d459ef37773 100644 --- a/test/cmdlineTests/standard_wrong_type_metadata/input.json +++ b/test/cmdlineTests/standard_wrong_type_metadata/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_type_optimizer/input.json b/test/cmdlineTests/standard_wrong_type_optimizer/input.json index b42ca550a5e0..f623628e9fd4 100644 --- a/test/cmdlineTests/standard_wrong_type_optimizer/input.json +++ b/test/cmdlineTests/standard_wrong_type_optimizer/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_type_output_selection/input.json b/test/cmdlineTests/standard_wrong_type_output_selection/input.json index a7b615d1c5a1..5f03fbf7bc63 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json b/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json index 9840a97e59e5..4004b2285b71 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json b/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json index 7ab12ba8ba53..9bfdb99ad9bf 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json b/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json index 3e5cd661859a..d5c51fa93854 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_remappings/input.json b/test/cmdlineTests/standard_wrong_type_remappings/input.json index 1436e01474c3..4d64b9e47fa9 100644 --- a/test/cmdlineTests/standard_wrong_type_remappings/input.json +++ b/test/cmdlineTests/standard_wrong_type_remappings/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json b/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json index c96611f3e07e..ee7fb52fa15e 100644 --- a/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json +++ b/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_settings/input.json b/test/cmdlineTests/standard_wrong_type_settings/input.json index 7cdb0881c5d4..638f57a76247 100644 --- a/test/cmdlineTests/standard_wrong_type_settings/input.json +++ b/test/cmdlineTests/standard_wrong_type_settings/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_type_source/input.json b/test/cmdlineTests/standard_wrong_type_source/input.json index d58504fe0e2b..f8c72996b4ba 100644 --- a/test/cmdlineTests/standard_wrong_type_source/input.json +++ b/test/cmdlineTests/standard_wrong_type_source/input.json @@ -6,7 +6,7 @@ "B": [1, 2, 3], "C": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json b/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json index be4272b6caf7..b96a17564071 100644 --- a/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json +++ b/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/input.json b/test/cmdlineTests/standard_yul_optimiserSteps/input.json new file mode 100644 index 000000000000..1015496f9364 --- /dev/null +++ b/test/cmdlineTests/standard_yul_optimiserSteps/input.json @@ -0,0 +1,26 @@ +{ + "language": "Yul", + "sources": + { + "A": + { + "content": "{ let x := mload(0) sstore(add(x, 0), 0) }" + } + }, + "settings": + { + "optimizer": { + "enabled": true, + "details": { + "yul": true, + "yulDetails": { + "optimizerSteps": "dhfoDgvulfnTUtnIf" + } + } + }, + "outputSelection": + { + "*": { "*": ["*"], "": [ "*" ] } + } + } +} diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/output.json b/test/cmdlineTests/standard_yul_optimiserSteps/output.json new file mode 100644 index 000000000000..383ad85571dd --- /dev/null +++ b/test/cmdlineTests/standard_yul_optimiserSteps/output.json @@ -0,0 +1,30 @@ +{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */ + 0x00 + /* \"A\":11:19 */ + mload + /* \"A\":38:39 */ + 0x00 + /* \"A\":34:35 */ + 0x00 + /* \"A\":31:32 */ + dup3 + /* \"A\":27:36 */ + add + /* \"A\":20:40 */ + sstore + pop +","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { + code { + let x := mload(0) + sstore(add(x, 0), 0) + } +} +","irOptimized":"object \"object\" { + code { + { + let x := mload(0) + sstore(add(x, 0), 0) + } + } +} +"}}},"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/storage_layout_bytes/input.json b/test/cmdlineTests/storage_layout_bytes/input.json index fe1468c53efa..cd69dd0edf55 100644 --- a/test/cmdlineTests/storage_layout_bytes/input.json +++ b/test/cmdlineTests/storage_layout_bytes/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { bytes s1 = \"test\"; bytes s2; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { bytes s1 = \"test\"; bytes s2; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_dyn_array/input.json b/test/cmdlineTests/storage_layout_dyn_array/input.json index 64ab3e20b4ae..2904a9cefe93 100644 --- a/test/cmdlineTests/storage_layout_dyn_array/input.json +++ b/test/cmdlineTests/storage_layout_dyn_array/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint[] array1; bool[] array2; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint[] array1; bool[] array2; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_many/input.json b/test/cmdlineTests/storage_layout_many/input.json index 7ea41f2117a7..90b4e25dd17d 100644 --- a/test/cmdlineTests/storage_layout_many/input.json +++ b/test/cmdlineTests/storage_layout_many/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; mapping (uint => mapping (address => bool)) map; uint[] array; string s1; bytes b1; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; mapping (uint => mapping (address => bool)) map; uint[] array; string s1; bytes b1; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_mapping/input.json b/test/cmdlineTests/storage_layout_mapping/input.json index 6292391d5c40..66ecff53736c 100644 --- a/test/cmdlineTests/storage_layout_mapping/input.json +++ b/test/cmdlineTests/storage_layout_mapping/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_smoke/input.json b/test/cmdlineTests/storage_layout_smoke/input.json index 47722e759462..90fd18101b28 100644 --- a/test/cmdlineTests/storage_layout_smoke/input.json +++ b/test/cmdlineTests/storage_layout_smoke/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json b/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json index b31f3dd9d24d..15cb774f5c2b 100644 --- a/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json +++ b/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" }, "fileB": { - "content": "contract A { uint x; uint y; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint x; uint y; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_string/input.json b/test/cmdlineTests/storage_layout_string/input.json index 834617b3a130..d069d309830b 100644 --- a/test/cmdlineTests/storage_layout_string/input.json +++ b/test/cmdlineTests/storage_layout_string/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { string s1 = \"test\"; string s2; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { string s1 = \"test\"; string s2; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_struct/input.json b/test/cmdlineTests/storage_layout_struct/input.json index 31ab020cf2b1..7353386df232 100644 --- a/test/cmdlineTests/storage_layout_struct/input.json +++ b/test/cmdlineTests/storage_layout_struct/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_struct_packed/input.json b/test/cmdlineTests/storage_layout_struct_packed/input.json index 80c706c7bbd9..e562a6a3adb7 100644 --- a/test/cmdlineTests/storage_layout_struct_packed/input.json +++ b/test/cmdlineTests/storage_layout_struct_packed/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_value_types/input.json b/test/cmdlineTests/storage_layout_value_types/input.json index 1477dde08a37..3f0dd709c192 100644 --- a/test/cmdlineTests/storage_layout_value_types/input.json +++ b/test/cmdlineTests/storage_layout_value_types/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint x; uint y; address addr; uint[2] array; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint x; uint y; address addr; uint[2] array; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_value_types_packed/input.json b/test/cmdlineTests/storage_layout_value_types_packed/input.json index 04a7bd3bfa72..18af8f50f32b 100644 --- a/test/cmdlineTests/storage_layout_value_types_packed/input.json +++ b/test/cmdlineTests/storage_layout_value_types_packed/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; }" } }, "settings": { diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/args b/test/cmdlineTests/strict_asm_optimizer_steps/args new file mode 100644 index 000000000000..ade406ee4bb2 --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/args @@ -0,0 +1 @@ +--strict-assembly --optimize --yul-optimizations dhfoDgvulfnTUtnIf diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/err b/test/cmdlineTests/strict_asm_optimizer_steps/err new file mode 100644 index 000000000000..014a1178fa22 --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/input.yul b/test/cmdlineTests/strict_asm_optimizer_steps/input.yul new file mode 100644 index 000000000000..b1c756df3048 --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/input.yul @@ -0,0 +1,27 @@ +object "C_6" { + code { + mstore(64, 128) + if callvalue() { revert(0, 0) } + codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + return(0, datasize("C_6_deployed")) + } + object "C_6_deployed" { + code { + { + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + pop(selector) + } + pop(iszero(calldatasize())) + revert(0, 0) + } + + function shift_right_224_unsigned(value) -> newValue + { + newValue := shr(224, value) + } + } + } +} diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/output b/test/cmdlineTests/strict_asm_optimizer_steps/output new file mode 100644 index 000000000000..369be348cacd --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/output @@ -0,0 +1,88 @@ + +======= strict_asm_optimizer_steps/input.yul (EVM) ======= + +Pretty printed source: +object "C_6" { + code { + { + mstore(64, 128) + if callvalue() { revert(0, 0) } + codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + return(0, datasize("C_6_deployed")) + } + } + object "C_6_deployed" { + code { + { + mstore(64, 128) + pop(iszero(lt(calldatasize(), 4))) + revert(0, 0) + } + } + } +} + + +Binary representation: +60806040523415600f5760006000fd5b6010601d60003960106000f3fe608060405260043610155060006000fd + +Text representation: + /* "strict_asm_optimizer_steps/input.yul":45:48 */ + 0x80 + /* "strict_asm_optimizer_steps/input.yul":41:43 */ + 0x40 + /* "strict_asm_optimizer_steps/input.yul":34:49 */ + mstore + /* "strict_asm_optimizer_steps/input.yul":61:72 */ + callvalue + /* "strict_asm_optimizer_steps/input.yul":58:60 */ + iszero + tag_1 + jumpi + /* "strict_asm_optimizer_steps/input.yul":85:86 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":82:83 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":75:87 */ + revert + /* "strict_asm_optimizer_steps/input.yul":58:60 */ +tag_1: + /* "strict_asm_optimizer_steps/input.yul":98:163 */ + dataSize(sub_0) + dataOffset(sub_0) + /* "strict_asm_optimizer_steps/input.yul":107:108 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":98:163 */ + codecopy + /* "strict_asm_optimizer_steps/input.yul":172:207 */ + dataSize(sub_0) + /* "strict_asm_optimizer_steps/input.yul":179:180 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":172:207 */ + return +stop + +sub_0: assembly { + /* "strict_asm_optimizer_steps/input.yul":298:301 */ + 0x80 + /* "strict_asm_optimizer_steps/input.yul":294:296 */ + 0x40 + /* "strict_asm_optimizer_steps/input.yul":287:302 */ + mstore + /* "strict_asm_optimizer_steps/input.yul":348:349 */ + 0x04 + /* "strict_asm_optimizer_steps/input.yul":332:346 */ + calldatasize + /* "strict_asm_optimizer_steps/input.yul":329:350 */ + lt + /* "strict_asm_optimizer_steps/input.yul":322:351 */ + iszero + /* "strict_asm_optimizer_steps/input.yul":319:321 */ + pop + /* "strict_asm_optimizer_steps/input.yul":570:571 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":567:568 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":560:572 */ + revert +} diff --git a/test/cmdlineTests/structured_documentation_source_location/err b/test/cmdlineTests/structured_documentation_source_location/err index 1081fdaa89a4..1f69adf4f63d 100644 --- a/test/cmdlineTests/structured_documentation_source_location/err +++ b/test/cmdlineTests/structured_documentation_source_location/err @@ -1,11 +1,11 @@ Error: Documentation tag "@return No value returned" does not contain the name of its return parameter. - --> structured_documentation_source_location/input.sol:3:5: + --> structured_documentation_source_location/input.sol:4:5: | -3 | /// @param id Some identifier +4 | /// @param id Some identifier | ^ (Relevant source part starts here and spans across multiple lines). Error: Documentation tag "@return No value returned" does not contain the name of its return parameter. - --> structured_documentation_source_location/input.sol:7:5: + --> structured_documentation_source_location/input.sol:8:5: | -7 | /// @return No value returned +8 | /// @return No value returned | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test/cmdlineTests/structured_documentation_source_location/input.sol b/test/cmdlineTests/structured_documentation_source_location/input.sol index ceec1354731c..399c2b8b89bd 100644 --- a/test/cmdlineTests/structured_documentation_source_location/input.sol +++ b/test/cmdlineTests/structured_documentation_source_location/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >= 0.0; abstract contract C { /// @param id Some identifier diff --git a/test/cmdlineTests/too_long_line/err b/test/cmdlineTests/too_long_line/err index 6e51190371ad..802cac3cb4ae 100644 --- a/test/cmdlineTests/too_long_line/err +++ b/test/cmdlineTests/too_long_line/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line/input.sol diff --git a/test/cmdlineTests/too_long_line_both_sides_short/err b/test/cmdlineTests/too_long_line_both_sides_short/err index 34bd25d28a07..131fab20921e 100644 --- a/test/cmdlineTests/too_long_line_both_sides_short/err +++ b/test/cmdlineTests/too_long_line_both_sides_short/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_both_sides_short/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_both_sides_short/input.sol diff --git a/test/cmdlineTests/too_long_line_edge_in/err b/test/cmdlineTests/too_long_line_edge_in/err index 2988bc44e578..83cd670e1f68 100644 --- a/test/cmdlineTests/too_long_line_edge_in/err +++ b/test/cmdlineTests/too_long_line_edge_in/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_edge_in/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_edge_in/input.sol diff --git a/test/cmdlineTests/too_long_line_edge_out/err b/test/cmdlineTests/too_long_line_edge_out/err index a85faa44fe82..7d3b54f21290 100644 --- a/test/cmdlineTests/too_long_line_edge_out/err +++ b/test/cmdlineTests/too_long_line_edge_out/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_edge_out/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_edge_out/input.sol diff --git a/test/cmdlineTests/too_long_line_left_short/err b/test/cmdlineTests/too_long_line_left_short/err index aa36b1068fe2..0f8c70e5a5fa 100644 --- a/test/cmdlineTests/too_long_line_left_short/err +++ b/test/cmdlineTests/too_long_line_left_short/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_left_short/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_left_short/input.sol diff --git a/test/cmdlineTests/too_long_line_multiline/err b/test/cmdlineTests/too_long_line_multiline/err index 2aa801623c39..6d8114ca8b92 100644 --- a/test/cmdlineTests/too_long_line_multiline/err +++ b/test/cmdlineTests/too_long_line_multiline/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_multiline/input.sol + Error: No visibility specified. Did you intend to add "public"? --> too_long_line_multiline/input.sol:2:5: | diff --git a/test/cmdlineTests/too_long_line_right_short/err b/test/cmdlineTests/too_long_line_right_short/err index d2d8f3980abd..6837dd8ab0c8 100644 --- a/test/cmdlineTests/too_long_line_right_short/err +++ b/test/cmdlineTests/too_long_line_right_short/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_right_short/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_right_short/input.sol diff --git a/test/cmdlineTests/yul_optimizer_steps/input.sol b/test/cmdlineTests/yul_optimizer_steps/input.sol index f787d2fcf147..a75662b25803 100644 --- a/test/cmdlineTests/yul_optimizer_steps/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol b/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol index 363a4c72182c..6923ca7023b3 100644 --- a/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol b/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol index 363a4c72182c..6923ca7023b3 100644 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol b/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol index 363a4c72182c..6923ca7023b3 100644 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol b/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol index 363a4c72182c..6923ca7023b3 100644 --- a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_string_format_ascii/input.json b/test/cmdlineTests/yul_string_format_ascii/input.json index c23c65b5a2d4..0eba555c953c 100644 --- a/test/cmdlineTests/yul_string_format_ascii/input.json +++ b/test/cmdlineTests/yul_string_format_ascii/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcabc\"; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcabc\"; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 81fa10ca70d7..0609704c5c59 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { @@ -37,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } @@ -106,7 +107,7 @@ object \"C_10\" { } } - function fun_f_9() -> vloc__4_mpos { + function fun_f_9() -> vloc__4_mpos { let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json index 247f665cb74f..3dbcdb819093 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (bytes32) { return \"abcabc\"; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (bytes32) { return \"abcabc\"; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index a171f87b59ce..1bc00b338d56 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { @@ -37,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } @@ -78,7 +79,7 @@ object \"C_10\" { converted := 0x6162636162630000000000000000000000000000000000000000000000000000 } - function fun_f_9() -> vloc__4 { + function fun_f_9() -> vloc__4 { let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32() vloc__4 := zero_value_for_type_t_bytes32_1 diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json index c7309f2afaf7..003dddfa7ae7 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0x61626364; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0x61626364; } }" } }, "settings": 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 3dccf690dc22..fdef7778120b 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 @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { @@ -37,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } @@ -82,7 +83,7 @@ object \"C_10\" { converted := shift_left_224(cleanup_t_rational_1633837924_by_1(value)) } - function fun_f_9() -> vloc__4 { + function fun_f_9() -> vloc__4 { let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() vloc__4 := zero_value_for_type_t_bytes4_1 diff --git a/test/cmdlineTests/yul_string_format_ascii_long/input.json b/test/cmdlineTests/yul_string_format_ascii_long/input.json index cf3b2a854472..5d91e402e416 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/input.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\"; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\"; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 77360e5a4631..2a845796da93 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { @@ -37,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } @@ -110,7 +111,7 @@ object \"C_10\" { } } - function fun_f_9() -> vloc__4_mpos { + function fun_f_9() -> vloc__4_mpos { let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos diff --git a/test/cmdlineTests/yul_string_format_hex/input.json b/test/cmdlineTests/yul_string_format_hex/input.json index 5ba723f56d2f..9bb3fd138f4a 100644 --- a/test/cmdlineTests/yul_string_format_hex/input.json +++ b/test/cmdlineTests/yul_string_format_hex/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 81853dadbe2b..784baf2f4655 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { @@ -37,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } @@ -82,7 +83,7 @@ object \"C_10\" { converted := shift_left_224(cleanup_t_rational_2864434397_by_1(value)) } - function fun_f_9() -> vloc__4 { + function fun_f_9() -> vloc__4 { let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() vloc__4 := zero_value_for_type_t_bytes4_1 diff --git a/test/evmc/README.md b/test/evmc/README.md index 436a47e684ed..1d5d55422cb7 100644 --- a/test/evmc/README.md +++ b/test/evmc/README.md @@ -1,3 +1,3 @@ # EVMC -This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.1.0](https://github.com/ethereum/evmc/releases/tag/v7.1.0). +This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.2.0](https://github.com/ethereum/evmc/releases/tag/v7.2.0). diff --git a/test/evmc/evmc.h b/test/evmc/evmc.h index 3fc3ca610d88..51d9f842a0da 100644 --- a/test/evmc/evmc.h +++ b/test/evmc/evmc.h @@ -345,8 +345,8 @@ struct evmc_result /** * The amount of gas left after the execution. * - * If evmc_result::code is not ::EVMC_SUCCESS nor ::EVMC_REVERT - * the value MUST be 0. + * If evmc_result::status_code is neither ::EVMC_SUCCESS nor ::EVMC_REVERT + * the value MUST be 0. */ int64_t gas_left; diff --git a/test/evmc/evmc.hpp b/test/evmc/evmc.hpp index 0b44cd12c298..36f9063b3a49 100644 --- a/test/evmc/evmc.hpp +++ b/test/evmc/evmc.hpp @@ -25,6 +25,33 @@ struct address : evmc_address /// Initializes bytes to zeros if not other @p init value provided. constexpr address(evmc_address init = {}) noexcept : evmc_address{init} {} + /// Converting constructor from unsigned integer value. + /// + /// This constructor assigns the @p v value to the last 8 bytes [12:19] + /// in big-endian order. + constexpr explicit address(uint64_t v) noexcept + : evmc_address{{0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + static_cast(v >> 56), + static_cast(v >> 48), + static_cast(v >> 40), + static_cast(v >> 32), + static_cast(v >> 24), + static_cast(v >> 16), + static_cast(v >> 8), + static_cast(v >> 0)}} + {} + /// Explicit operator converting to bool. constexpr inline explicit operator bool() const noexcept; }; @@ -39,6 +66,45 @@ struct bytes32 : evmc_bytes32 /// Initializes bytes to zeros if not other @p init value provided. constexpr bytes32(evmc_bytes32 init = {}) noexcept : evmc_bytes32{init} {} + /// Converting constructor from unsigned integer value. + /// + /// This constructor assigns the @p v value to the last 8 bytes [24:31] + /// in big-endian order. + constexpr explicit bytes32(uint64_t v) noexcept + : evmc_bytes32{{0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + static_cast(v >> 56), + static_cast(v >> 48), + static_cast(v >> 40), + static_cast(v >> 32), + static_cast(v >> 24), + static_cast(v >> 16), + static_cast(v >> 8), + static_cast(v >> 0)}} + {} + /// Explicit operator converting to bool. constexpr inline explicit operator bool() const noexcept; }; @@ -50,7 +116,6 @@ using uint256be = bytes32; /// Loads 64 bits / 8 bytes of data from the given @p bytes array in big-endian order. constexpr inline uint64_t load64be(const uint8_t* bytes) noexcept { - // TODO: Report bug in clang incorrectly optimizing this with AVX2 enabled. return (uint64_t{bytes[0]} << 56) | (uint64_t{bytes[1]} << 48) | (uint64_t{bytes[2]} << 40) | (uint64_t{bytes[3]} << 32) | (uint64_t{bytes[4]} << 24) | (uint64_t{bytes[5]} << 16) | (uint64_t{bytes[6]} << 8) | uint64_t{bytes[7]}; @@ -76,7 +141,7 @@ constexpr inline uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept } // namespace fnv -/// The "equal" comparison operator for the evmc::address type. +/// The "equal to" comparison operator for the evmc::address type. constexpr bool operator==(const address& a, const address& b) noexcept { // TODO: Report bug in clang keeping unnecessary bswap. @@ -85,23 +150,41 @@ constexpr bool operator==(const address& a, const address& b) noexcept load32be(&a.bytes[16]) == load32be(&b.bytes[16]); } -/// The "not equal" comparison operator for the evmc::address type. +/// The "not equal to" comparison operator for the evmc::address type. constexpr bool operator!=(const address& a, const address& b) noexcept { return !(a == b); } -/// The "less" comparison operator for the evmc::address type. +/// The "less than" comparison operator for the evmc::address type. constexpr bool operator<(const address& a, const address& b) noexcept { return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load32be(&a.bytes[16]) < load32be(&b.bytes[16])); + (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || + (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && + load32be(&a.bytes[16]) < load32be(&b.bytes[16])))); +} + +/// The "greater than" comparison operator for the evmc::address type. +constexpr bool operator>(const address& a, const address& b) noexcept +{ + return b < a; +} + +/// The "less than or equal to" comparison operator for the evmc::address type. +constexpr bool operator<=(const address& a, const address& b) noexcept +{ + return !(b < a); +} + +/// The "greater than or equal to" comparison operator for the evmc::address type. +constexpr bool operator>=(const address& a, const address& b) noexcept +{ + return !(a < b); } -/// The "equal" comparison operator for the evmc::bytes32 type. +/// The "equal to" comparison operator for the evmc::bytes32 type. constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept { return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && @@ -110,22 +193,40 @@ constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept load64be(&a.bytes[24]) == load64be(&b.bytes[24]); } -/// The "not equal" comparison operator for the evmc::bytes32 type. +/// The "not equal to" comparison operator for the evmc::bytes32 type. constexpr bool operator!=(const bytes32& a, const bytes32& b) noexcept { return !(a == b); } -/// The "less" comparison operator for the evmc::bytes32 type. +/// The "less than" comparison operator for the evmc::bytes32 type. constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept { return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load64be(&a.bytes[16]) < load64be(&b.bytes[16])) || - (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && - load64be(&a.bytes[24]) < load64be(&b.bytes[24])); + (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || + (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && + (load64be(&a.bytes[16]) < load64be(&b.bytes[16]) || + (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && + load64be(&a.bytes[24]) < load64be(&b.bytes[24])))))); +} + +/// The "greater than" comparison operator for the evmc::bytes32 type. +constexpr bool operator>(const bytes32& a, const bytes32& b) noexcept +{ + return b < a; +} + +/// The "less than or equal to" comparison operator for the evmc::bytes32 type. +constexpr bool operator<=(const bytes32& a, const bytes32& b) noexcept +{ + return !(b < a); +} + +/// The "greater than or equal to" comparison operator for the evmc::bytes32 type. +constexpr bool operator>=(const bytes32& a, const bytes32& b) noexcept +{ + return !(a < b); } /// Checks if the given address is the zero address. @@ -154,108 +255,72 @@ namespace literals { namespace internal { -template -struct integer_sequence +constexpr size_t length(const char* s) noexcept { -}; - -template -using byte_sequence = integer_sequence; - -template -using char_sequence = integer_sequence; - - -template -struct concatenate; - -template -struct concatenate, byte_sequence> -{ - using type = byte_sequence; -}; - -template -constexpr uint8_t parse_hex_digit() noexcept -{ - static_assert((D >= '0' && D <= '9') || (D >= 'a' && D <= 'f') || (D >= 'A' && D <= 'F'), - "literal must be hexadecimal integer"); - return static_cast( - (D >= '0' && D <= '9') ? D - '0' : (D >= 'a' && D <= 'f') ? D - 'a' + 10 : D - 'A' + 10); + return (*s != '\0') ? length(s + 1) + 1 : 0; } - -template -struct parse_digits; - -template -struct parse_digits> +constexpr int from_hex(char c) noexcept { - using type = byte_sequence(parse_hex_digit() << 4) | - parse_hex_digit()>; -}; - -template -struct parse_digits> -{ - using type = typename concatenate>::type, - typename parse_digits>::type>::type; -}; - - -template -struct parse_literal; + return (c >= 'a' && c <= 'f') ? c - ('a' - 10) : + (c >= 'A' && c <= 'F') ? c - ('A' - 10) : c - '0'; +} -template -struct parse_literal> +constexpr uint8_t byte(const char* s, size_t i) noexcept { - static_assert(Prefix1 == '0' && Prefix2 == 'x', "literal must be in hexadecimal notation"); - static_assert(sizeof...(Literal) == sizeof(T) * 2, "literal must match the result type size"); + return static_cast((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1])); +} - template - static constexpr T create_from(byte_sequence) noexcept - { - return T{{{Bytes...}}}; - } +template +T from_hex(const char*) noexcept; - static constexpr T get() noexcept - { - return create_from(typename parse_digits>::type{}); - } -}; +template <> +constexpr bytes32 from_hex(const char* s) noexcept +{ + return { + {{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6), + byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13), + byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19), byte(s, 20), + byte(s, 21), byte(s, 22), byte(s, 23), byte(s, 24), byte(s, 25), byte(s, 26), byte(s, 27), + byte(s, 28), byte(s, 29), byte(s, 30), byte(s, 31)}}}; +} -template -struct parse_literal> +template <> +constexpr address from_hex
(const char* s) noexcept { - static_assert(Digit == '0', "only 0 is allowed as a single digit literal"); - static constexpr T get() noexcept { return {}; } -}; + return { + {{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6), + byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13), + byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19)}}}; +} -template -constexpr T parse() noexcept +template +constexpr T from_literal(const char* s) { - return parse_literal>::get(); + return (s[0] == '0' && s[1] == '\0') ? + T{} : + !(s[0] == '0' && s[1] == 'x') ? + throw "literal must be in hexadecimal notation" : + (length(s + 2) != sizeof(T) * 2) ? throw "literal must match the result type size" : + from_hex(s + 2); } } // namespace internal /// Literal for evmc::address. -template -constexpr address operator"" _address() noexcept +constexpr address operator""_address(const char* s) noexcept { - return internal::parse(); + return internal::from_literal
(s); } /// Literal for evmc::bytes32. -template -constexpr bytes32 operator"" _bytes32() noexcept +constexpr bytes32 operator""_bytes32(const char* s) noexcept { - return internal::parse(); + return internal::from_literal(s); } } // namespace literals using namespace literals; - /// Alias for evmc_make_result(). constexpr auto make_result = evmc_make_result; @@ -626,6 +691,13 @@ class VM m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)}; } + /// Returns the pointer to C EVMC struct representing the VM. + /// + /// Gives access to the C EVMC VM struct to allow advanced interaction with the VM not supported + /// by the C++ interface. Use as the last resort. + /// This object still owns the VM after returning the pointer. The returned pointer MAY be null. + evmc_vm* get_raw_pointer() const noexcept { return m_instance; } + private: evmc_vm* m_instance = nullptr; }; diff --git a/test/evmc/mocked_host.hpp b/test/evmc/mocked_host.hpp index 2ff1701a4416..57f0cb79b20e 100644 --- a/test/evmc/mocked_host.hpp +++ b/test/evmc/mocked_host.hpp @@ -133,10 +133,11 @@ class MockedHost : public Host /// The record of all SELFDESTRUCTs from the selfdestruct() method. std::vector recorded_selfdestructs; -protected: +private: /// The copy of call inputs for the recorded_calls record. std::vector m_recorded_calls_inputs; +public: /// Record an account access. /// @param addr The address of the accessed account. void record_account_access(const address& addr) const diff --git a/test/externalTests/colony.sh b/test/externalTests/colony.sh index 66231eb99125..559703ae78dc 100755 --- a/test/externalTests/colony.sh +++ b/test/externalTests/colony.sh @@ -34,12 +34,12 @@ function colony_test FORCE_ABIv2=false CONFIG="truffle.js" - truffle_setup https://github.com/erak/colonyNetwork.git develop_060 + truffle_setup https://github.com/solidity-external-tests/colonyNetwork.git develop_060 run_install install_fn cd lib rm -Rf dappsys - git clone https://github.com/erak/dappsys-monolithic.git -b master_060 dappsys + git clone https://github.com/solidity-external-tests/dappsys-monolithic.git -b master_060 dappsys cd .. truffle_run_test compile_fn test_fn diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index b2bb657cb220..b7887721177c 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -33,10 +33,10 @@ function gnosis_safe_test OPTIMIZER_LEVEL=1 CONFIG="truffle.js" - truffle_setup https://github.com/erak/safe-contracts.git development_060 + truffle_setup https://github.com/solidity-external-tests/safe-contracts.git development_060 force_truffle_version - sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:erak/mock-contract#master_060|g' package.json + sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_060|g' package.json run_install install_fn replace_libsolc_call @@ -45,4 +45,3 @@ function gnosis_safe_test } external_test Gnosis-Safe gnosis_safe_test - diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 49b6c3e42940..7c82cd281413 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -33,7 +33,7 @@ function zeppelin_test OPTIMIZER_LEVEL=1 CONFIG="truffle-config.js" - truffle_setup https://github.com/erak/openzeppelin-contracts.git master_060 + truffle_setup https://github.com/OpenZeppelin/openzeppelin-contracts.git master run_install install_fn truffle_run_test compile_fn test_fn diff --git a/test/libsolidity/ABIJson/internal_constructor.sol b/test/libsolidity/ABIJson/internal_constructor.sol new file mode 100644 index 000000000000..7f8ea5ed2e00 --- /dev/null +++ b/test/libsolidity/ABIJson/internal_constructor.sol @@ -0,0 +1,9 @@ +// bug #8712 +contract B { + uint immutable x; + constructor(function() internal returns(uint) fp) internal { + x = fp(); } +} +// ---- +// :B +// [] diff --git a/test/libsolidity/ABIJsonTest.cpp b/test/libsolidity/ABIJsonTest.cpp index d144e2ee7d0c..a46c1d470bc9 100644 --- a/test/libsolidity/ABIJsonTest.cpp +++ b/test/libsolidity/ABIJsonTest.cpp @@ -45,7 +45,10 @@ TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefi { CompilerStack compiler; - compiler.setSources({{"", "pragma solidity >=0.0;\n" + m_source}}); + compiler.setSources({{ + "", + "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n" + m_source + }}); compiler.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); compiler.setOptimiserSettings(solidity::test::CommonOptions::get().optimize); if (!compiler.parseAndAnalyze()) diff --git a/test/libsolidity/ASTJSON/abstract_contract.json b/test/libsolidity/ASTJSON/abstract_contract.json index da9fd1196fb9..32b414e8a577 100644 --- a/test/libsolidity/ASTJSON/abstract_contract.json +++ b/test/libsolidity/ASTJSON/abstract_contract.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/abstract_contract_legacy.json b/test/libsolidity/ASTJSON/abstract_contract_legacy.json index 66d1c0e8b962..13f046eecb55 100644 --- a/test/libsolidity/ASTJSON/abstract_contract_legacy.json +++ b/test/libsolidity/ASTJSON/abstract_contract_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json index ef965ac79324..a82fa0b82a55 100644 --- a/test/libsolidity/ASTJSON/address_payable.json +++ b/test/libsolidity/ASTJSON/address_payable.json @@ -8,6 +8,7 @@ ] }, "id": 40, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/address_payable_legacy.json b/test/libsolidity/ASTJSON/address_payable_legacy.json index dd33e6408eaf..7fe404f3e71a 100644 --- a/test/libsolidity/ASTJSON/address_payable_legacy.json +++ b/test/libsolidity/ASTJSON/address_payable_legacy.json @@ -8,7 +8,8 @@ [ 39 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/array_type_name.json b/test/libsolidity/ASTJSON/array_type_name.json index e97518cb8267..a09bc306ad12 100644 --- a/test/libsolidity/ASTJSON/array_type_name.json +++ b/test/libsolidity/ASTJSON/array_type_name.json @@ -8,6 +8,7 @@ ] }, "id": 5, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/array_type_name_legacy.json b/test/libsolidity/ASTJSON/array_type_name_legacy.json index 37175bb3706e..cc1c7a77aa17 100644 --- a/test/libsolidity/ASTJSON/array_type_name_legacy.json +++ b/test/libsolidity/ASTJSON/array_type_name_legacy.json @@ -8,7 +8,8 @@ [ 4 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/call.json b/test/libsolidity/ASTJSON/assembly/call.json index 1c2a4bf7ea1b..ad81c1094784 100644 --- a/test/libsolidity/ASTJSON/assembly/call.json +++ b/test/libsolidity/ASTJSON/assembly/call.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/call_legacy.json b/test/libsolidity/ASTJSON/assembly/call_legacy.json index 619d132bceb6..93ad1b956576 100644 --- a/test/libsolidity/ASTJSON/assembly/call_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/call_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/empty_block.json b/test/libsolidity/ASTJSON/assembly/empty_block.json index 575b1f7f4ce3..847fd408583b 100644 --- a/test/libsolidity/ASTJSON/assembly/empty_block.json +++ b/test/libsolidity/ASTJSON/assembly/empty_block.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json b/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json index 108a76a00342..74d24d5e1e8e 100644 --- a/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/function.json b/test/libsolidity/ASTJSON/assembly/function.json index 7e98952614fa..6bd37162d89d 100644 --- a/test/libsolidity/ASTJSON/assembly/function.json +++ b/test/libsolidity/ASTJSON/assembly/function.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/function_legacy.json b/test/libsolidity/ASTJSON/assembly/function_legacy.json index 163d8d05ad65..ee6918d251b1 100644 --- a/test/libsolidity/ASTJSON/assembly/function_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/function_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/leave.json b/test/libsolidity/ASTJSON/assembly/leave.json index c8ef5eaee9bc..5868c1acb9a6 100644 --- a/test/libsolidity/ASTJSON/assembly/leave.json +++ b/test/libsolidity/ASTJSON/assembly/leave.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/leave_legacy.json b/test/libsolidity/ASTJSON/assembly/leave_legacy.json index 35ce02f554b4..2c39fba3782e 100644 --- a/test/libsolidity/ASTJSON/assembly/leave_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/leave_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/loop.json b/test/libsolidity/ASTJSON/assembly/loop.json index b815da447c54..263db400d276 100644 --- a/test/libsolidity/ASTJSON/assembly/loop.json +++ b/test/libsolidity/ASTJSON/assembly/loop.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/loop_legacy.json b/test/libsolidity/ASTJSON/assembly/loop_legacy.json index cf4095dd80a5..5085e4c5044a 100644 --- a/test/libsolidity/ASTJSON/assembly/loop_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/loop_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions.json b/test/libsolidity/ASTJSON/assembly/nested_functions.json index f52cbfc084c3..5abb7fce4cf9 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions.json @@ -8,6 +8,7 @@ ] }, "id": 9, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json b/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json index c0164e3f7745..0ccfcf85a4e5 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json @@ -8,7 +8,8 @@ [ 8 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/slot_offset.json b/test/libsolidity/ASTJSON/assembly/slot_offset.json index 75c22243cf28..7231747c4d2a 100644 --- a/test/libsolidity/ASTJSON/assembly/slot_offset.json +++ b/test/libsolidity/ASTJSON/assembly/slot_offset.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json b/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json index 083f8dd52f7d..574c7ad75ad3 100644 --- a/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/stringlit.json b/test/libsolidity/ASTJSON/assembly/stringlit.json index a7a596e0c563..7fd0b9b84a24 100644 --- a/test/libsolidity/ASTJSON/assembly/stringlit.json +++ b/test/libsolidity/ASTJSON/assembly/stringlit.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json b/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json index bb7a5c5c3014..76c503925b34 100644 --- a/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch.json b/test/libsolidity/ASTJSON/assembly/switch.json index 854c5b6cdce0..61b462f1ea48 100644 --- a/test/libsolidity/ASTJSON/assembly/switch.json +++ b/test/libsolidity/ASTJSON/assembly/switch.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.json b/test/libsolidity/ASTJSON/assembly/switch_default.json index c0bf264388ed..2f15a82c5536 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json index 2d5caa0fa446..18e7c860c17d 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_legacy.json index 5b9322f4c97d..dab33b305c49 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/switch_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/var_access.json b/test/libsolidity/ASTJSON/assembly/var_access.json index 0ef180ceda64..c44940a28474 100644 --- a/test/libsolidity/ASTJSON/assembly/var_access.json +++ b/test/libsolidity/ASTJSON/assembly/var_access.json @@ -8,6 +8,7 @@ ] }, "id": 10, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/var_access_legacy.json b/test/libsolidity/ASTJSON/assembly/var_access_legacy.json index 21cda71e8ee3..a80a24613d8a 100644 --- a/test/libsolidity/ASTJSON/assembly/var_access_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/var_access_legacy.json @@ -8,7 +8,8 @@ [ 9 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/constructor.json b/test/libsolidity/ASTJSON/constructor.json index 5e6059b294b1..321d93471538 100644 --- a/test/libsolidity/ASTJSON/constructor.json +++ b/test/libsolidity/ASTJSON/constructor.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/constructor_legacy.json b/test/libsolidity/ASTJSON/constructor_legacy.json index 53265f7116f2..9417561a7bbe 100644 --- a/test/libsolidity/ASTJSON/constructor_legacy.json +++ b/test/libsolidity/ASTJSON/constructor_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/contract_dep_order.json b/test/libsolidity/ASTJSON/contract_dep_order.json index 6b269800f705..b4a93ff75af0 100644 --- a/test/libsolidity/ASTJSON/contract_dep_order.json +++ b/test/libsolidity/ASTJSON/contract_dep_order.json @@ -24,6 +24,7 @@ ] }, "id": 14, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/contract_dep_order_legacy.json b/test/libsolidity/ASTJSON/contract_dep_order_legacy.json index 11ccbed7a41e..75ac151e85f4 100644 --- a/test/libsolidity/ASTJSON/contract_dep_order_legacy.json +++ b/test/libsolidity/ASTJSON/contract_dep_order_legacy.json @@ -24,7 +24,8 @@ [ 13 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/documentation.json b/test/libsolidity/ASTJSON/documentation.json index 8671978b062e..782409abfd96 100644 --- a/test/libsolidity/ASTJSON/documentation.json +++ b/test/libsolidity/ASTJSON/documentation.json @@ -8,6 +8,7 @@ ] }, "id": 3, + "license": null, "nodeType": "SourceUnit", "nodes": [ @@ -48,6 +49,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ @@ -88,6 +90,7 @@ ] }, "id": 21, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/documentation_legacy.json b/test/libsolidity/ASTJSON/documentation_legacy.json index 90866e7fbd91..70a4d8cf42c1 100644 --- a/test/libsolidity/ASTJSON/documentation_legacy.json +++ b/test/libsolidity/ASTJSON/documentation_legacy.json @@ -8,7 +8,8 @@ [ 20 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/enum_value.json b/test/libsolidity/ASTJSON/enum_value.json index 981b54210556..bb8e1289b909 100644 --- a/test/libsolidity/ASTJSON/enum_value.json +++ b/test/libsolidity/ASTJSON/enum_value.json @@ -8,6 +8,7 @@ ] }, "id": 5, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/enum_value_legacy.json b/test/libsolidity/ASTJSON/enum_value_legacy.json index 0c1c0b8e22c4..eeff347d722f 100644 --- a/test/libsolidity/ASTJSON/enum_value_legacy.json +++ b/test/libsolidity/ASTJSON/enum_value_legacy.json @@ -8,7 +8,8 @@ [ 4 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/event_definition.json b/test/libsolidity/ASTJSON/event_definition.json index e58a6b8432d2..e5c5749738be 100644 --- a/test/libsolidity/ASTJSON/event_definition.json +++ b/test/libsolidity/ASTJSON/event_definition.json @@ -8,6 +8,7 @@ ] }, "id": 4, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/event_definition_legacy.json b/test/libsolidity/ASTJSON/event_definition_legacy.json index 30dfb7069984..330f586ae229 100644 --- a/test/libsolidity/ASTJSON/event_definition_legacy.json +++ b/test/libsolidity/ASTJSON/event_definition_legacy.json @@ -8,7 +8,8 @@ [ 3 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/fallback.json b/test/libsolidity/ASTJSON/fallback.json index 128888701c40..7c83f871f4d3 100644 --- a/test/libsolidity/ASTJSON/fallback.json +++ b/test/libsolidity/ASTJSON/fallback.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json b/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json index 353d512f77ee..801a4e148be0 100644 --- a/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json +++ b/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json @@ -8,6 +8,7 @@ ] }, "id": 10, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json b/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json index 7d1aa7ae4501..44e02c42dd3e 100644 --- a/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json +++ b/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json @@ -8,7 +8,8 @@ [ 9 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/fallback_legacy.json b/test/libsolidity/ASTJSON/fallback_legacy.json index 8c84c57fcc5e..8c81e87d86a3 100644 --- a/test/libsolidity/ASTJSON/fallback_legacy.json +++ b/test/libsolidity/ASTJSON/fallback_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/fallback_payable.json b/test/libsolidity/ASTJSON/fallback_payable.json index 8facda351ffb..fb55b60774df 100644 --- a/test/libsolidity/ASTJSON/fallback_payable.json +++ b/test/libsolidity/ASTJSON/fallback_payable.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/fallback_payable_legacy.json b/test/libsolidity/ASTJSON/fallback_payable_legacy.json index 74e4242fd1be..2bc5a9659d4c 100644 --- a/test/libsolidity/ASTJSON/fallback_payable_legacy.json +++ b/test/libsolidity/ASTJSON/fallback_payable_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/function_type.json b/test/libsolidity/ASTJSON/function_type.json index e1e83a3165b8..57f061b3901e 100644 --- a/test/libsolidity/ASTJSON/function_type.json +++ b/test/libsolidity/ASTJSON/function_type.json @@ -8,6 +8,7 @@ ] }, "id": 18, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/function_type_legacy.json b/test/libsolidity/ASTJSON/function_type_legacy.json index e86eb16a6932..799e94bf9ae5 100644 --- a/test/libsolidity/ASTJSON/function_type_legacy.json +++ b/test/libsolidity/ASTJSON/function_type_legacy.json @@ -8,7 +8,8 @@ [ 17 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/global_enum.json b/test/libsolidity/ASTJSON/global_enum.json index 1b0ffe3778d9..876b55ddf347 100644 --- a/test/libsolidity/ASTJSON/global_enum.json +++ b/test/libsolidity/ASTJSON/global_enum.json @@ -8,6 +8,7 @@ ] }, "id": 3, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/global_enum_legacy.json b/test/libsolidity/ASTJSON/global_enum_legacy.json index f29649018688..aea0583457f0 100644 --- a/test/libsolidity/ASTJSON/global_enum_legacy.json +++ b/test/libsolidity/ASTJSON/global_enum_legacy.json @@ -8,7 +8,8 @@ [ 2 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/global_struct.json b/test/libsolidity/ASTJSON/global_struct.json index 64cf62a532db..e1802e03b828 100644 --- a/test/libsolidity/ASTJSON/global_struct.json +++ b/test/libsolidity/ASTJSON/global_struct.json @@ -8,6 +8,7 @@ ] }, "id": 4, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/global_struct_legacy.json b/test/libsolidity/ASTJSON/global_struct_legacy.json index ef0f71c37ada..2670ea5ea5df 100644 --- a/test/libsolidity/ASTJSON/global_struct_legacy.json +++ b/test/libsolidity/ASTJSON/global_struct_legacy.json @@ -8,7 +8,8 @@ [ 3 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/inheritance_specifier.json b/test/libsolidity/ASTJSON/inheritance_specifier.json index 2a235d1ed550..20da9e31c2b7 100644 --- a/test/libsolidity/ASTJSON/inheritance_specifier.json +++ b/test/libsolidity/ASTJSON/inheritance_specifier.json @@ -12,6 +12,7 @@ ] }, "id": 5, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json b/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json index a387355b4ae6..b8de3a97bae1 100644 --- a/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json +++ b/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json @@ -12,7 +12,8 @@ [ 4 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/license.json b/test/libsolidity/ASTJSON/license.json new file mode 100644 index 000000000000..e8c6616a3cd5 --- /dev/null +++ b/test/libsolidity/ASTJSON/license.json @@ -0,0 +1,35 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 1 + ] + }, + "id": 2, + "license": "GPL-3.0", + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "id": 1, + "linearizedBaseContracts": + [ + 1 + ], + "name": "C", + "nodeType": "ContractDefinition", + "nodes": [], + "scope": 2, + "src": "36:13:1" + } + ], + "src": "36:14:1" +} diff --git a/test/libsolidity/ASTJSON/license.sol b/test/libsolidity/ASTJSON/license.sol new file mode 100644 index 000000000000..92ffb8fa642f --- /dev/null +++ b/test/libsolidity/ASTJSON/license.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 +contract C {} + +// ---- diff --git a/test/libsolidity/ASTJSON/license_legacy.json b/test/libsolidity/ASTJSON/license_legacy.json new file mode 100644 index 000000000000..2f1405b62cef --- /dev/null +++ b/test/libsolidity/ASTJSON/license_legacy.json @@ -0,0 +1,50 @@ +{ + "attributes": + { + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 1 + ] + }, + "license": "GPL-3.0" + }, + "children": + [ + { + "attributes": + { + "abstract": false, + "baseContracts": + [ + null + ], + "contractDependencies": + [ + null + ], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "linearizedBaseContracts": + [ + 1 + ], + "name": "C", + "nodes": + [ + null + ], + "scope": 2 + }, + "id": 1, + "name": "ContractDefinition", + "src": "36:13:1" + } + ], + "id": 2, + "name": "SourceUnit", + "src": "36:14:1" +} diff --git a/test/libsolidity/ASTJSON/long_type_name_binary_operation.json b/test/libsolidity/ASTJSON/long_type_name_binary_operation.json index 6e025f5f9423..5e13c2bfb58e 100644 --- a/test/libsolidity/ASTJSON/long_type_name_binary_operation.json +++ b/test/libsolidity/ASTJSON/long_type_name_binary_operation.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json b/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json index 6ad38d194bf5..c6f7662eac44 100644 --- a/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json +++ b/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_identifier.json b/test/libsolidity/ASTJSON/long_type_name_identifier.json index eddeacd0436d..417972b45d90 100644 --- a/test/libsolidity/ASTJSON/long_type_name_identifier.json +++ b/test/libsolidity/ASTJSON/long_type_name_identifier.json @@ -8,6 +8,7 @@ ] }, "id": 16, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json b/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json index bc90e0d6ac93..537746abd719 100644 --- a/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json +++ b/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json @@ -8,7 +8,8 @@ [ 15 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/mappings.json b/test/libsolidity/ASTJSON/mappings.json index 5c24e3a12061..8df004d4ba35 100644 --- a/test/libsolidity/ASTJSON/mappings.json +++ b/test/libsolidity/ASTJSON/mappings.json @@ -8,6 +8,7 @@ ] }, "id": 18, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/mappings_legacy.json b/test/libsolidity/ASTJSON/mappings_legacy.json index 700097b66bfb..49737edeebff 100644 --- a/test/libsolidity/ASTJSON/mappings_legacy.json +++ b/test/libsolidity/ASTJSON/mappings_legacy.json @@ -8,7 +8,8 @@ [ 17 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/modifier_definition.json b/test/libsolidity/ASTJSON/modifier_definition.json index a3c71159a48c..c5070f1da8ba 100644 --- a/test/libsolidity/ASTJSON/modifier_definition.json +++ b/test/libsolidity/ASTJSON/modifier_definition.json @@ -8,6 +8,7 @@ ] }, "id": 15, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/modifier_definition_legacy.json b/test/libsolidity/ASTJSON/modifier_definition_legacy.json index 369562171ea7..05876ae3e3c2 100644 --- a/test/libsolidity/ASTJSON/modifier_definition_legacy.json +++ b/test/libsolidity/ASTJSON/modifier_definition_legacy.json @@ -8,7 +8,8 @@ [ 14 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/modifier_invocation.json b/test/libsolidity/ASTJSON/modifier_invocation.json index a3c71159a48c..c5070f1da8ba 100644 --- a/test/libsolidity/ASTJSON/modifier_invocation.json +++ b/test/libsolidity/ASTJSON/modifier_invocation.json @@ -8,6 +8,7 @@ ] }, "id": 15, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/modifier_invocation_legacy.json b/test/libsolidity/ASTJSON/modifier_invocation_legacy.json index 369562171ea7..05876ae3e3c2 100644 --- a/test/libsolidity/ASTJSON/modifier_invocation_legacy.json +++ b/test/libsolidity/ASTJSON/modifier_invocation_legacy.json @@ -8,7 +8,8 @@ [ 14 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/mutability.json b/test/libsolidity/ASTJSON/mutability.json index 81d66870244c..3f5d610ed2a3 100644 --- a/test/libsolidity/ASTJSON/mutability.json +++ b/test/libsolidity/ASTJSON/mutability.json @@ -8,6 +8,7 @@ ] }, "id": 11, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/mutability_legacy.json b/test/libsolidity/ASTJSON/mutability_legacy.json index 98f28f636e21..387ebc267772 100644 --- a/test/libsolidity/ASTJSON/mutability_legacy.json +++ b/test/libsolidity/ASTJSON/mutability_legacy.json @@ -8,7 +8,8 @@ [ 10 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/non_utf8.json b/test/libsolidity/ASTJSON/non_utf8.json index c925389d7b61..d716d91c2d77 100644 --- a/test/libsolidity/ASTJSON/non_utf8.json +++ b/test/libsolidity/ASTJSON/non_utf8.json @@ -8,6 +8,7 @@ ] }, "id": 9, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/non_utf8_legacy.json b/test/libsolidity/ASTJSON/non_utf8_legacy.json index d3a212b0c242..d49d2013d812 100644 --- a/test/libsolidity/ASTJSON/non_utf8_legacy.json +++ b/test/libsolidity/ASTJSON/non_utf8_legacy.json @@ -8,7 +8,8 @@ [ 8 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/override.json b/test/libsolidity/ASTJSON/override.json index cb3d0268bab7..3e5a8c9da52b 100644 --- a/test/libsolidity/ASTJSON/override.json +++ b/test/libsolidity/ASTJSON/override.json @@ -16,6 +16,7 @@ ] }, "id": 32, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/override_legacy.json b/test/libsolidity/ASTJSON/override_legacy.json index a9bece4acd7d..23cf18b2bfda 100644 --- a/test/libsolidity/ASTJSON/override_legacy.json +++ b/test/libsolidity/ASTJSON/override_legacy.json @@ -16,7 +16,8 @@ [ 31 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/placeholder_statement.json b/test/libsolidity/ASTJSON/placeholder_statement.json index 4b37ba4174c9..3be70c463e1b 100644 --- a/test/libsolidity/ASTJSON/placeholder_statement.json +++ b/test/libsolidity/ASTJSON/placeholder_statement.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/placeholder_statement_legacy.json b/test/libsolidity/ASTJSON/placeholder_statement_legacy.json index f478862f4abb..7ab1f48799de 100644 --- a/test/libsolidity/ASTJSON/placeholder_statement_legacy.json +++ b/test/libsolidity/ASTJSON/placeholder_statement_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/receive_ether.json b/test/libsolidity/ASTJSON/receive_ether.json index f861e4271733..a837dae157d1 100644 --- a/test/libsolidity/ASTJSON/receive_ether.json +++ b/test/libsolidity/ASTJSON/receive_ether.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/receive_ether_legacy.json b/test/libsolidity/ASTJSON/receive_ether_legacy.json index e8f025234272..964bd991b840 100644 --- a/test/libsolidity/ASTJSON/receive_ether_legacy.json +++ b/test/libsolidity/ASTJSON/receive_ether_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/short_type_name.json b/test/libsolidity/ASTJSON/short_type_name.json index 75defa9ab69f..54c9b99eac65 100644 --- a/test/libsolidity/ASTJSON/short_type_name.json +++ b/test/libsolidity/ASTJSON/short_type_name.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/short_type_name_legacy.json b/test/libsolidity/ASTJSON/short_type_name_legacy.json index 0d428bcb1f31..c813bcdf42a3 100644 --- a/test/libsolidity/ASTJSON/short_type_name_legacy.json +++ b/test/libsolidity/ASTJSON/short_type_name_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/short_type_name_ref.json b/test/libsolidity/ASTJSON/short_type_name_ref.json index 46096a914dbd..1a22f1f2435d 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref.json @@ -8,6 +8,7 @@ ] }, "id": 13, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json b/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json index b1f4b88d266f..086a215848d7 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json @@ -8,7 +8,8 @@ [ 12 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/smoke.json b/test/libsolidity/ASTJSON/smoke.json index 9aa2eda01894..d72018e090d3 100644 --- a/test/libsolidity/ASTJSON/smoke.json +++ b/test/libsolidity/ASTJSON/smoke.json @@ -8,6 +8,7 @@ ] }, "id": 2, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/smoke_legacy.json b/test/libsolidity/ASTJSON/smoke_legacy.json index a3254c4e80e7..da56b0e772af 100644 --- a/test/libsolidity/ASTJSON/smoke_legacy.json +++ b/test/libsolidity/ASTJSON/smoke_legacy.json @@ -8,7 +8,8 @@ [ 1 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/source_location.json b/test/libsolidity/ASTJSON/source_location.json index 54bffe378df1..b0b81d8f8a12 100644 --- a/test/libsolidity/ASTJSON/source_location.json +++ b/test/libsolidity/ASTJSON/source_location.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/source_location_legacy.json b/test/libsolidity/ASTJSON/source_location_legacy.json index dbd578dd2b1d..42f81ad1614e 100644 --- a/test/libsolidity/ASTJSON/source_location_legacy.json +++ b/test/libsolidity/ASTJSON/source_location_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/two_base_functions.json b/test/libsolidity/ASTJSON/two_base_functions.json index 7e6e15395ec8..18412bbc7849 100644 --- a/test/libsolidity/ASTJSON/two_base_functions.json +++ b/test/libsolidity/ASTJSON/two_base_functions.json @@ -16,6 +16,7 @@ ] }, "id": 23, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/two_base_functions_legacy.json b/test/libsolidity/ASTJSON/two_base_functions_legacy.json index bc9e4545cda9..b58008b75909 100644 --- a/test/libsolidity/ASTJSON/two_base_functions_legacy.json +++ b/test/libsolidity/ASTJSON/two_base_functions_legacy.json @@ -16,7 +16,8 @@ [ 22 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/using_for_directive.json b/test/libsolidity/ASTJSON/using_for_directive.json index 9b973141cf1d..66674f5899b9 100644 --- a/test/libsolidity/ASTJSON/using_for_directive.json +++ b/test/libsolidity/ASTJSON/using_for_directive.json @@ -12,6 +12,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/using_for_directive_legacy.json b/test/libsolidity/ASTJSON/using_for_directive_legacy.json index 13df0d5c2a64..280e9be4aebd 100644 --- a/test/libsolidity/ASTJSON/using_for_directive_legacy.json +++ b/test/libsolidity/ASTJSON/using_for_directive_legacy.json @@ -12,7 +12,8 @@ [ 1 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp index be14d1cf149b..80c20c760733 100644 --- a/test/libsolidity/AnalysisFramework.cpp +++ b/test/libsolidity/AnalysisFramework.cpp @@ -44,13 +44,17 @@ pair AnalysisFramework::parseAnalyseAndReturnError( string const& _source, bool _reportWarnings, - bool _insertVersionPragma, + bool _insertLicenseAndVersionPragma, bool _allowMultipleErrors, bool _allowRecoveryErrors ) { compiler().reset(); - compiler().setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}}); + compiler().setSources({{"", + _insertLicenseAndVersionPragma ? + "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n" + _source : + _source + }}); compiler().setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); compiler().setParserErrorRecovery(_allowRecoveryErrors); _allowMultipleErrors = _allowMultipleErrors || _allowRecoveryErrors; diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h index 26ca9e916540..db75ad3017a1 100644 --- a/test/libsolidity/AnalysisFramework.h +++ b/test/libsolidity/AnalysisFramework.h @@ -47,7 +47,7 @@ class AnalysisFramework parseAnalyseAndReturnError( std::string const& _source, bool _reportWarnings = false, - bool _insertVersionPragma = true, + bool _insertLicenseAndVersionPragma = true, bool _allowMultipleErrors = false, bool _allowRecoveryErrors = false ); diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index 1fa0bf712042..252b7759be17 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(string_storage) // This is only correct on >=Constantinople. else if (CommonOptions::get().useABIEncoderV2) { - if (CommonOptions::get().optimizeYul) + if (CommonOptions::get().optimize) { // Costs with 0 are cases which cannot be triggered in tests. if (evmVersion < EVMVersion::istanbul()) @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(string_storage) // This is only correct on >=Constantinople. else if (CommonOptions::get().useABIEncoderV2) { - if (CommonOptions::get().optimizeYul) + if (CommonOptions::get().optimize) { if (evmVersion < EVMVersion::istanbul()) CHECK_GAS(0, 21567, 20); diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 79394855a510..09e257664546 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -43,7 +43,8 @@ class GasMeterTestFramework: public SolidityExecutionFramework void compile(string const& _sourceCode) { m_compiler.reset(); - m_compiler.setSources({{"", "pragma solidity >=0.0;\n" + _sourceCode}}); + m_compiler.setSources({{"", "pragma solidity >=0.0;\n" + "// SPDX-License-Identifier: GPL-3.0\n" + _sourceCode}}); m_compiler.setOptimiserSettings(solidity::test::CommonOptions::get().optimize); m_compiler.setEVMVersion(m_evmVersion); BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed"); diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 694839b99ef3..893a20715f2e 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -100,7 +100,7 @@ void GasTest::printUpdatedExpectations(ostream& _stream, string const& _linePref TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) { - string const versionPragma = "pragma solidity >=0.0;\n"; + string const preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; compiler().reset(); // Prerelease CBOR metadata varies in size due to changing version numbers and build dates. // This leads to volatile creation cost estimates. Therefore we force the compiler to @@ -114,7 +114,7 @@ TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, b } settings.expectedExecutionsPerDeployment = m_optimiseRuns; compiler().setOptimiserSettings(settings); - compiler().setSources({{"", versionPragma + m_source}}); + compiler().setSources({{"", preamble + m_source}}); if (!compiler().parseAndAnalyze() || !compiler().compile()) { diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp index 6df19c1c7ac7..66398381ef7f 100644 --- a/test/libsolidity/SMTChecker.cpp +++ b/test/libsolidity/SMTChecker.cpp @@ -38,7 +38,7 @@ class SMTCheckerFramework: public AnalysisFramework parseAnalyseAndReturnError( std::string const& _source, bool _reportWarnings = false, - bool _insertVersionPragma = true, + bool _insertLicenseAndVersionPragma = true, bool _allowMultipleErrors = false, bool _allowRecoveryErrors = false ) override @@ -46,7 +46,7 @@ class SMTCheckerFramework: public AnalysisFramework return AnalysisFramework::parseAnalyseAndReturnError( "pragma experimental SMTChecker;\n" + _source, _reportWarnings, - _insertVersionPragma, + _insertLicenseAndVersionPragma, _allowMultipleErrors, _allowRecoveryErrors ); diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index a1c23662ad0c..484db13fff0e 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -64,8 +64,8 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li StandardCompiler compiler; // Run the compiler and retrieve the smtlib2queries (1st run) - string versionPragma = "pragma solidity >=0.0;\n"; - Json::Value input = buildJson(versionPragma); + string preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; + Json::Value input = buildJson(preamble); Json::Value result = compiler.compile(input); // This is the list of query hashes requested by the 1st run @@ -121,10 +121,10 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li std::string sourceName; if (location.isMember("source") && location["source"].isString()) sourceName = location["source"].asString(); - if (start >= static_cast(versionPragma.size())) - start -= versionPragma.size(); - if (end >= static_cast(versionPragma.size())) - end -= versionPragma.size(); + if (start >= static_cast(preamble.size())) + start -= preamble.size(); + if (end >= static_cast(preamble.size())) + end -= preamble.size(); m_errorList.emplace_back(SyntaxTestError{ error["type"].asString(), error["message"].asString(), diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index ded01f8dd2a3..33d40c899c6a 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -13,6 +13,8 @@ */ #include +#include +#include #include #include #include @@ -27,6 +29,7 @@ using namespace std; using namespace solidity; +using namespace solidity::yul; using namespace solidity::util; using namespace solidity::util::formatting; using namespace solidity::frontend::test; @@ -36,9 +39,10 @@ using namespace boost::unit_test; namespace fs = boost::filesystem; -SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion): +SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul): SolidityExecutionFramework(_evmVersion), - EVMVersionRestrictedTestCase(_filename) + EVMVersionRestrictedTestCase(_filename), + m_enforceViaYul(enforceViaYul) { m_source = m_reader.source(); m_lineOffset = m_reader.lineNumber(); @@ -78,112 +82,155 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) { - for(bool compileViaYul: set{!m_runWithoutYul, m_runWithYul}) + + for (bool compileViaYul: set{!m_runWithoutYul, m_runWithYul || m_enforceViaYul}) { - reset(); - bool success = true; + try + { + reset(); + bool success = true; - m_compileViaYul = compileViaYul; - if (compileViaYul) - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl; + m_compileViaYul = compileViaYul; + m_compileViaYulCanBeSet = false; - for (auto& test: m_tests) - test.reset(); + if (compileViaYul) + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl; - map libraries; + for (auto& test: m_tests) + test.reset(); - bool constructed = false; + map libraries; - for (auto& test: m_tests) - { - if (constructed) - { - soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); - soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments."); - } - else if (test.call().isLibrary) - { - soltestAssert( - deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, - "Failed to deploy library " + test.call().signature - ); - libraries[test.call().signature] = m_contractAddress; - continue; - } - else - { - if (test.call().isConstructor) - deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries); - else - soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); - constructed = true; - } + bool constructed = false; - if (test.call().isConstructor) - { - if (m_transactionSuccessful == test.call().expectations.failure) - success = false; - - test.setFailure(!m_transactionSuccessful); - test.setRawBytes(bytes()); - } - else + for (auto& test: m_tests) { - bytes output; - if (test.call().useCallWithoutSignature) - output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value); - else + if (constructed) + { + soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); + soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments."); + } + else if (test.call().isLibrary) { soltestAssert( - m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), - "The function " + test.call().signature + " is not known to the compiler" + deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, + "Failed to deploy library " + test.call().signature ); + libraries[test.call().signature] = m_contractAddress; + continue; + } + else + { + if (test.call().isConstructor) + deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries); + else + soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); + constructed = true; + } - output = callContractFunctionWithValueNoEncoding( - test.call().signature, - test.call().value.value, - test.call().arguments.rawBytes() - ); + if (test.call().isConstructor) + { + if (m_transactionSuccessful == test.call().expectations.failure) + success = false; + + test.setFailure(!m_transactionSuccessful); + test.setRawBytes(bytes()); } + else + { + bytes output; + if (test.call().useCallWithoutSignature) + output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value); + else + { + soltestAssert( + m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), + "The function " + test.call().signature + " is not known to the compiler" + ); - if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes())) - success = false; + output = callContractFunctionWithValueNoEncoding( + test.call().signature, + test.call().value.value, + test.call().arguments.rawBytes() + ); + } - test.setFailure(!m_transactionSuccessful); - test.setRawBytes(std::move(output)); - test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName())); - } - } + if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes())) + success = false; - if (!success) - { - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; - for (auto const& test: m_tests) - { - ErrorReporter errorReporter; - _stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl; - _stream << errorReporter.format(_linePrefix, _formatted); + test.setFailure(!m_transactionSuccessful); + test.setRawBytes(std::move(output)); + test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName())); + } } - _stream << endl; - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; - for (auto const& test: m_tests) + + if (success && !m_runWithYul && compileViaYul) { - ErrorReporter errorReporter; - _stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl; - _stream << errorReporter.format(_linePrefix, _formatted); + m_compileViaYulCanBeSet = true; + AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix + << "Test can pass via Yul and marked with compileViaYul: false." << endl; + return TestResult::Failure; } - AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix - << "Attention: Updates on the test will apply the detected format displayed." << endl; - if (compileViaYul && m_runWithoutYul) + + if (!success && (m_runWithYul || !compileViaYul)) { - _stream << _linePrefix << endl << _linePrefix; - AnsiColorized(_stream, _formatted, {RED_BACKGROUND}) << "Note that the test passed without Yul."; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + for (auto const& test: m_tests) + { + ErrorReporter errorReporter; + _stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl; + _stream << errorReporter.format(_linePrefix, _formatted); + } _stream << endl; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + for (auto const& test: m_tests) + { + ErrorReporter errorReporter; + _stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl; + _stream << errorReporter.format(_linePrefix, _formatted); + } + AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix + << "Attention: Updates on the test will apply the detected format displayed." << endl; + if (compileViaYul && m_runWithoutYul) + { + _stream << _linePrefix << endl << _linePrefix; + AnsiColorized(_stream, _formatted, {RED_BACKGROUND}) + << "Note that the test passed without Yul."; + _stream << endl; + } + else if (!compileViaYul && m_runWithYul) + AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix + << "Note that the test also has to pass via Yul." << endl; + return TestResult::Failure; } - else if (!compileViaYul && m_runWithYul) - AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix - << "Note that the test also has to pass via Yul." << endl; - return TestResult::Failure; + } + catch (WhiskersError const&) + { + // this is an error in Whiskers template, so should be thrown anyway + throw; + } + catch (YulException const&) + { + // this should be an error in yul compilation or translation + throw; + } + catch (boost::exception const&) + { + if (compileViaYul && !m_runWithYul) + continue; + throw; + } + catch (std::exception const&) + { + if (compileViaYul && !m_runWithYul) + continue; + throw; + } + catch (...) + { + if (compileViaYul && !m_runWithYul) + continue; + throw; } } @@ -204,6 +251,20 @@ void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) con _stream << test.format("", true, false) << endl; } +void SemanticTest::printUpdatedSettings(ostream& _stream, string const& _linePrefix) +{ + auto& settings = m_reader.settings(); + if (settings.empty() && !m_compileViaYulCanBeSet) + return; + + _stream << _linePrefix << "// ====" << endl; + if (m_compileViaYulCanBeSet) + _stream << _linePrefix << "// compileViaYul: also\n"; + for (auto const& setting: settings) + if (!m_compileViaYulCanBeSet || setting.first != "compileViaYul") + _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; +} + void SemanticTest::parseExpectations(istream& _stream) { TestFileParser parser{_stream}; diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index 94c29e193efd..870d61d568e2 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -40,13 +40,14 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict { public: static std::unique_ptr create(Config const& _options) - { return std::make_unique(_options.filename, _options.evmVersion); } + { return std::make_unique(_options.filename, _options.evmVersion, _options.enforceCompileViaYul); } - explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion); + explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, bool _enforceViaYul = false); TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override; void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix = "") const override; + void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = "") override; /// Instantiates a test file parser that parses the additional comment section at the end of /// the input stream \param _stream. Each function call is represented using a `FunctionCallTest` @@ -64,8 +65,10 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict std::vector m_tests; bool m_runWithYul = false; bool m_runWithoutYul = true; + bool m_enforceViaYul = false; bool m_runWithABIEncoderV1Only = false; bool m_allowNonExistingFunctions = false; + bool m_compileViaYulCanBeSet = false; }; } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 26d9ca98997a..b97d7bd4d675 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -370,6 +370,7 @@ BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible) BOOST_AUTO_TEST_CASE(warn_nonpresent_pragma) { char const* text = R"( + // SPDX-License-Identifier: GPL-3.0 contract C {} )"; auto sourceAndError = parseAnalyseAndReturnError(text, true, false); diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 13bd1f3b06f2..69ae832ad631 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -355,6 +355,27 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) checkNatspec(sourceCode, "test", natspec, false); } +BOOST_AUTO_TEST_CASE(dev_return_no_params) +{ + char const* sourceCode = R"( + contract test { + /// @return d The result of the multiplication + function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; } + } + )"; + + char const* natspec = R"ABCDEF( + { + "methods": { + "mul(uint256,uint256)": { + "returns": { "d": "The result of the multiplication" + } + } + })ABCDEF"; + + checkNatspec(sourceCode, "test", natspec, false); +} + BOOST_AUTO_TEST_CASE(dev_return) { char const* sourceCode = R"( diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp index b21c8f2e11ac..bc9f169046ac 100644 --- a/test/libsolidity/SolidityTypes.cpp +++ b/test/libsolidity/SolidityTypes.cpp @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers) ModifierDefinition mod(++id, SourceLocation{}, make_shared("modif"), {}, emptyParams, {}, {}, {}); BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$"); - SourceUnit su(++id, {}, {}); + SourceUnit su(++id, {}, {}, {}); BOOST_CHECK_EQUAL(ModuleType(su).identifier(), "t_module_7"); BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Block).identifier(), "t_magic_block"); BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Message).identifier(), "t_magic_message"); diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index ce9a29268581..5f4a4e3d4cea 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -427,7 +427,7 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK(result["sources"]["fileA"]["legacyAST"].isObject()); BOOST_CHECK_EQUAL( util::jsonCompactPrint(result["sources"]["fileA"]["legacyAST"]), - "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},\"children\":" + "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]},\"license\":null},\"children\":" "[{\"attributes\":{\"abstract\":false,\"baseContracts\":[null],\"contractDependencies\":[null],\"contractKind\":\"contract\"," "\"documentation\":null,\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nodes\":[null],\"scope\":2}," "\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}" @@ -1105,6 +1105,46 @@ BOOST_AUTO_TEST_CASE(metadata_without_compilation) BOOST_CHECK(solidity::test::isValidMetadata(contract["metadata"].asString())); } + +BOOST_AUTO_TEST_CASE(license_in_metadata) +{ + string const input = R"( + { + "language": "Solidity", + "sources": { + "fileA": { "content": "import \"fileB\"; contract A { } // SPDX-License-Identifier: GPL-3.0 \n" }, + "fileB": { "content": "import \"fileC\"; /* SPDX-License-Identifier: MIT */ contract B { }" }, + "fileC": { "content": "import \"fileD\"; /* SPDX-License-Identifier: MIT AND GPL-3.0 */ contract C { }" }, + "fileD": { "content": "// SPDX-License-Identifier: (GPL-3.0+ OR MIT) AND MIT \n import \"fileE\"; contract D { }" }, + "fileE": { "content": "import \"fileF\"; /// SPDX-License-Identifier: MIT \n contract E { }" }, + "fileF": { "content": "/*\n * SPDX-License-Identifier: MIT\n */ contract F { }" } + }, + "settings": { + "outputSelection": { + "fileA": { + "*": [ "metadata" ] + } + } + } + } + )"; + Json::Value result = compile(input); + BOOST_CHECK(containsAtMostWarnings(result)); + Json::Value contract = getContractResult(result, "fileA", "A"); + BOOST_CHECK(contract.isObject()); + BOOST_CHECK(contract["metadata"].isString()); + Json::Value metadata; + BOOST_REQUIRE(util::jsonParseStrict(contract["metadata"].asString(), metadata)); + BOOST_CHECK_EQUAL(metadata["sources"]["fileA"]["license"], "GPL-3.0"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileB"]["license"], "MIT"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileC"]["license"], "MIT AND GPL-3.0"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileD"]["license"], "(GPL-3.0+ OR MIT) AND MIT"); + // This is actually part of the docstring, but still picked up + // because the source location of the contract does not cover the docstring. + BOOST_CHECK_EQUAL(metadata["sources"]["fileE"]["license"], "MIT"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileF"]["license"], "MIT"); +} + BOOST_AUTO_TEST_CASE(common_pattern) { char const* input = R"( diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 3ec506998490..55a77ed3090f 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -52,11 +52,11 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix void SyntaxTest::setupCompiler() { - string const versionPragma = "pragma solidity >=0.0;\n"; + string const preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; compiler().reset(); auto sourcesWithPragma = m_sources; for (auto& source: sourcesWithPragma) - source.second = versionPragma + source.second; + source.second = preamble + source.second; compiler().setSources(sourcesWithPragma); compiler().setEVMVersion(m_evmVersion); compiler().setParserErrorRecovery(m_parserErrorRecovery); @@ -89,18 +89,18 @@ void SyntaxTest::parseAndAnalyze() void SyntaxTest::filterObtainedErrors() { - string const versionPragma = "pragma solidity >=0.0;\n"; + string const preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; for (auto const& currentError: filterErrors(compiler().errors(), true)) { int locationStart = -1, locationEnd = -1; string sourceName; if (auto location = boost::get_error_info(*currentError)) { - // ignore the version pragma inserted by the testing tool when calculating locations. - if (location->start >= static_cast(versionPragma.size())) - locationStart = location->start - versionPragma.size(); - if (location->end >= static_cast(versionPragma.size())) - locationEnd = location->end - versionPragma.size(); + // ignore the version & license pragma inserted by the testing tool when calculating locations. + if (location->start >= static_cast(preamble.size())) + locationStart = location->start - (preamble.size()); + if (location->end >= static_cast(preamble.size())) + locationEnd = location->end - (preamble.size()); if (location->source) sourceName = location->source->name(); } diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol index ac17cf80e532..61c6658ac9b2 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol @@ -28,6 +28,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f0() -> 0x20, 0x0 // f1() -> 0x20, 0x40, 0x1, 0x2 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol index d73db5da6228..d11914fce439 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol @@ -22,5 +22,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol new file mode 100644 index 000000000000..917704e53a2e --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol @@ -0,0 +1,62 @@ +contract C { + function enc_packed_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(data[start:end]); + } + function enc_packed_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(bytes(data[start:end])); + } + + function enc_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(data[start:end]); + } + function enc_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(bytes(data[start:end])); + } + + function enc_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + function enc_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + + function enc_packed_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + function enc_packed_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + + function compare(bytes memory x, bytes memory y) internal { + assert(x.length == y.length); + for (uint i = 0; i < x.length; ++i) + assert(x[i] == y[i]); + } + + function test_bytes() public { + bytes memory test = new bytes(3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_bytes(test, i, j), this.enc_packed_bytes_reference(test, i, j)); + compare(this.enc_bytes(test, i, j), this.enc_bytes_reference(test, i, j)); + } + } + + function test_uint256() public { + uint256[] memory test = new uint256[](3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_uint256(test, i, j), this.enc_packed_uint256_reference(test, i, j)); + compare(this.enc_uint256(test, i, j), this.enc_uint256_reference(test, i, j)); + } + } +} +// ==== +// EVMVersion: >homestead +// ---- +// test_bytes() -> +// test_uint256() -> diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol index 704fd54dcf89..133645cff443 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol new file mode 100644 index 000000000000..1f14446723c7 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol @@ -0,0 +1,63 @@ +pragma experimental ABIEncoderV2; +contract C { + function enc_packed_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(data[start:end]); + } + function enc_packed_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(bytes(data[start:end])); + } + + function enc_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(data[start:end]); + } + function enc_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(bytes(data[start:end])); + } + + function enc_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + function enc_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + + function enc_packed_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + function enc_packed_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + + function compare(bytes memory x, bytes memory y) internal { + assert(x.length == y.length); + for (uint i = 0; i < x.length; ++i) + assert(x[i] == y[i]); + } + + function test_bytes() public { + bytes memory test = new bytes(3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_bytes(test, i, j), this.enc_packed_bytes_reference(test, i, j)); + compare(this.enc_bytes(test, i, j), this.enc_bytes_reference(test, i, j)); + } + } + + function test_uint256() public { + uint256[] memory test = new uint256[](3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_uint256(test, i, j), this.enc_packed_uint256_reference(test, i, j)); + compare(this.enc_uint256(test, i, j), this.enc_uint256_reference(test, i, j)); + } + } +} +// ==== +// EVMVersion: >homestead +// ---- +// test_bytes() -> +// test_uint256() -> diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol index 373334ee7f2a..405d34c5a137 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol @@ -9,5 +9,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol index 55047880a9b0..1074a1d0438f 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol @@ -8,5 +8,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol index b2076b370971..c47af87f4ad8 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol @@ -21,6 +21,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol index f2224c803cf5..92067f8db540 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol @@ -21,6 +21,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol index a89b6336a32e..0ded29febf58 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol @@ -5,6 +5,8 @@ contract C { return 23; } } +// ==== +// compileViaYul: also // ---- // f(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 23 # this is the common encoding for x.length == 1 && x[0][0].length == 0 && x[0][1].length == 0 # // f(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 23 # exotic, but still valid encoding # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol index d5802d1b190e..c777b12fd541 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol @@ -7,6 +7,8 @@ contract C { return this.f(x); } } +// ==== +// compileViaYul: also // ---- // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 42 // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 42 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol index f981a6e463b3..f50f59d1f76d 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol @@ -21,6 +21,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol index 9c6386e315e1..3a6fd9151985 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol @@ -15,6 +15,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol index 4bf181db3394..d23dfecfb3bc 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol @@ -15,6 +15,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol index 02322d504416..ce2f7a39067e 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol @@ -10,6 +10,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol index 16ba406307ba..51674081e136 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol index a4d1af66d215..45a89c483a84 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol index 29ff15692f4b..0ae57dbed332 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol index f369321c3623..6d747fdf0b5e 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f((uint256)): 3 -> 32, 32, 3 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol index 4bd9c2f77fe1..efb5045fc969 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol @@ -10,6 +10,8 @@ contract C { return this.g(x); } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> 0 // g(address): 0 -> 0 # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol index 94d4dbb11e62..eb9ce5962886 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol @@ -10,6 +10,8 @@ contract C { return this.gggg(x); } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> false // gggg(bool): 0 -> false # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol index f8824e271282..294a666e9024 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol @@ -42,6 +42,8 @@ contract C { return this.g16(x); } } +// ==== +// compileViaYul: also // ---- // f1(bytes32): left(0) -> left(0) // gg1(bytes1): left(0) -> left(0) # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol index 51ecd3432cc7..15cd07d496e2 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol @@ -42,6 +42,8 @@ contract C { return this.g128(x); } } +// ==== +// compileViaYul: also // ---- // f8(int256): 0 -> 0 // ggg8(int8): 0 -> 0 # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol index ee0ec362e46e..9788431e1e40 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol @@ -42,6 +42,8 @@ contract C { return this.g128(x); } } +// ==== +// compileViaYul: also // ---- // f8(uint256): 0 -> 0 // ggg8(uint8): 0 -> 0 # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol index a9402aa8641e..a56956a90fe2 100644 --- a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol +++ b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol @@ -1,6 +1,7 @@ contract Lotto { uint256 public constant ticketPrice = 555; } - +// ==== +// compileViaYul: also // ---- // ticketPrice() -> 555 diff --git a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol index d1e9f5c20211..ea2aa3d8f485 100644 --- a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol +++ b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol @@ -8,5 +8,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // test() -> 0 diff --git a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol index 7585980e1142..c70f195bab0d 100644 --- a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol +++ b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol @@ -18,6 +18,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> FAILURE // g(uint256): 0 -> FAILURE diff --git a/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol index 127320fc676e..0ccc0acb5e48 100644 --- a/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol +++ b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol @@ -7,7 +7,8 @@ contract C { return a % b; } } - +// ==== +// compileViaYul: also // ---- // div(uint256,uint256): 7, 2 -> 3 // div(uint256,uint256): 7, 0 -> FAILURE # throws # diff --git a/test/libsolidity/semanticTests/array/array_pop.sol b/test/libsolidity/semanticTests/array/array_pop.sol index 5667b61d411c..9e64119e98f7 100644 --- a/test/libsolidity/semanticTests/array/array_pop.sol +++ b/test/libsolidity/semanticTests/array/array_pop.sol @@ -11,6 +11,7 @@ contract c { l = data.length; } } - +// ==== +// compileViaYul: also // ---- // test() -> 1, 0 diff --git a/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol index 8fc018d72c5f..9f436d2d2b3b 100644 --- a/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol +++ b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol @@ -6,6 +6,7 @@ contract c { return true; } } - +// ==== +// compileViaYul: also // ---- // test() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/array_pop_isolated.sol b/test/libsolidity/semanticTests/array/array_pop_isolated.sol index 2e6eac83e524..58c56adc9b87 100644 --- a/test/libsolidity/semanticTests/array/array_pop_isolated.sol +++ b/test/libsolidity/semanticTests/array/array_pop_isolated.sol @@ -8,6 +8,7 @@ contract c { x = 3; } } - +// ==== +// compileViaYul: also // ---- // test() -> 3 diff --git a/test/libsolidity/semanticTests/array/array_push.sol b/test/libsolidity/semanticTests/array/array_push.sol index bd8200a37dec..5923580fae20 100644 --- a/test/libsolidity/semanticTests/array/array_push.sol +++ b/test/libsolidity/semanticTests/array/array_push.sol @@ -14,6 +14,7 @@ contract c { z = data[2]; } } - +// ==== +// compileViaYul: also // ---- // test() -> 5, 4, 3, 3 diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol index 30ffa3a4c67c..08aea4254e5e 100644 --- a/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol +++ b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol @@ -9,6 +9,5 @@ contract c { return true; } } - // ---- // test() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol index a9e3fd383bac..1635071c52d4 100644 --- a/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol +++ b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol @@ -8,6 +8,7 @@ contract c { x = 3; } } - +// ==== +// compileViaYul: also // ---- // test() -> 3 diff --git a/test/libsolidity/semanticTests/array/calldata_array.sol b/test/libsolidity/semanticTests/array/calldata_array.sol index c9c6dbda0981..9fdd8b44bd5b 100644 --- a/test/libsolidity/semanticTests/array/calldata_array.sol +++ b/test/libsolidity/semanticTests/array/calldata_array.sol @@ -11,6 +11,7 @@ contract C { b = s[1]; } } - +// ==== +// compileViaYul: also // ---- // f(uint256[2]): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol index d643d39739f0..cab938d6c7c3 100644 --- a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol +++ b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol @@ -11,7 +11,8 @@ contract C { return 42; } } - +// ==== +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 0x0 -> 42 # valid access stub # // f(uint256[][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # diff --git a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol index 3efd177b2ca4..d4c02df5ee5c 100644 --- a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol +++ b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol @@ -16,7 +16,8 @@ contract C { return 42; } } - +// ==== +// compileViaYul: also // ---- // f(uint256[][1][]): 0x20, 0x0 -> 42 # valid access stub # // f(uint256[][1][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # diff --git a/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol index 7c2ccde6e28e..a529a767da84 100644 --- a/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol +++ b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol @@ -4,6 +4,7 @@ contract C { return 7; } } - +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol b/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol index c42f8486217b..541a037a20e2 100644 --- a/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol +++ b/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol @@ -19,6 +19,8 @@ contract C { y[0] = 23; return x[2]; }} +// ==== +// compileViaYul: also // ---- // f() -> FAILURE // g() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol index 731fb43128b7..9e57f251cf9b 100644 --- a/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol +++ b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol @@ -29,6 +29,7 @@ contract C { return 0; } } - +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol index af14b48b4016..2ac334c17f5b 100644 --- a/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol +++ b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol @@ -12,7 +12,8 @@ contract A { return true; } } - +// ==== +// compileViaYul: also // ---- // test() -> false // testIt() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol index ff13db5be126..e85cb599ea38 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol @@ -7,7 +7,8 @@ contract Creator { ch = s[2]; } } - +// ==== +// compileViaYul: also // ---- // constructor(): 1, 2, 3, 4 -> // r() -> 4 diff --git a/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol index 7a6afbae7de3..ffeab647f93f 100644 --- a/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol +++ b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol @@ -5,6 +5,7 @@ contract C { return (x.length, bytes16(uint128(2)).length, a.length + 7); } } - +// ==== +// compileViaYul: also // ---- // f(bytes32): "789" -> 32, 16, 8 diff --git a/test/libsolidity/semanticTests/array/function_memory_array.sol b/test/libsolidity/semanticTests/array/function_memory_array.sol index cc6b3cf468e3..9ff4cad33e98 100644 --- a/test/libsolidity/semanticTests/array/function_memory_array.sol +++ b/test/libsolidity/semanticTests/array/function_memory_array.sol @@ -30,7 +30,8 @@ contract C { return arr[i](x); } } - +// ==== +// compileViaYul: also // ---- // test(uint256,uint256): 10, 0 -> 11 // test(uint256,uint256): 10, 1 -> 12 diff --git a/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol b/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol index 7a8a18670ea5..7de7f49be65b 100644 --- a/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol +++ b/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol @@ -10,5 +10,7 @@ contract Test { return data; } } +// ==== +// compileViaYul: also // ---- // f() -> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07 diff --git a/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol index b641ec1daa9c..fd1fba0a1a95 100644 --- a/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol +++ b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol @@ -11,7 +11,8 @@ contract C { return rows[n][k - 1]; } } - +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 3, 1 -> 1 // f(uint256,uint256): 9, 5 -> 70 diff --git a/test/libsolidity/semanticTests/array/push_no_args_1d.sol b/test/libsolidity/semanticTests/array/push_no_args_1d.sol index cf6f0687d910..daf8d43b14a0 100644 --- a/test/libsolidity/semanticTests/array/push_no_args_1d.sol +++ b/test/libsolidity/semanticTests/array/push_no_args_1d.sol @@ -19,6 +19,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // l() -> 0 // lv(uint256): 42 -> diff --git a/test/libsolidity/semanticTests/array/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol index b2876eeb335a..994a31db9ef2 100644 --- a/test/libsolidity/semanticTests/array/reusing_memory.sol +++ b/test/libsolidity/semanticTests/array/reusing_memory.sol @@ -22,5 +22,7 @@ contract Main { return map[a]; } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 diff --git a/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol index 2fc479d0e10a..a1bdf323686a 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol @@ -5,5 +5,7 @@ contract C { return x; } } +// ==== +// compileViaYul: also // ---- // f() -> 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 diff --git a/test/libsolidity/semanticTests/builtinFunctions/blockhash.sol b/test/libsolidity/semanticTests/builtinFunctions/blockhash.sol new file mode 100644 index 000000000000..075e6c395862 --- /dev/null +++ b/test/libsolidity/semanticTests/builtinFunctions/blockhash.sol @@ -0,0 +1,17 @@ +contract C { + function f() public returns(bytes32) { + return blockhash(1); + } + function g() public returns(bytes32) { + return blockhash(2); + } + function h() public returns(bytes32) { + return blockhash(3); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x3737373737373737373737373737373737373737373737373737373737373738 +// g() -> 0x3737373737373737373737373737373737373737373737373737373737373739 +// h() -> 0x373737373737373737373737373737373737373737373737373737373737373a diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol index 972aee839e0e..4a31c671588f 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol @@ -3,5 +3,7 @@ contract c { d = keccak256(abi.encodePacked(a, b, c)); } } +// ==== +// compileViaYul: also // ---- // foo(uint256,uint256,uint256): 0xa, 0xc, 0xd -> 0xbc740a98aae5923e8f04c9aa798c9ee82f69e319997699f2782c40828db9fd81 diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol index 01397f55f85e..958975966bf1 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol @@ -3,5 +3,7 @@ contract c { d = keccak256(abi.encodePacked(a, b, uint8(145))); } } +// ==== +// compileViaYul: also // ---- // foo(uint256,uint16): 0xa, 0xc -> 0x88acd45f75907e7c560318bc1a5249850a0999c4896717b1167d05d116e6dbad diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol index b157178fb857..c4e0b7d09a63 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol @@ -7,6 +7,8 @@ contract c { d = keccak256(abi.encodePacked(a, b, uint8(145), "foo")); } } +// ==== +// compileViaYul: also // ---- // foo() -> 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d // bar(uint256,uint16): 0xa, 0xc -> 0x6990f36476dc412b1c4baa48e2d9f4aa4bb313f61fda367c8fdbbb2232dc6146 diff --git a/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol index ededa2fabf20..bb9fc36161fa 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol @@ -3,7 +3,5 @@ contract C { return sha256(""); } } -// ==== -// compileViaYul: also // ---- // f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol b/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol index a8fd898333c4..69b590828518 100644 --- a/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol +++ b/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol @@ -11,6 +11,8 @@ contract C { _out = _in; } } +// ==== +// compileViaYul: also // ---- // f(bool): 0x0 -> 0x0 // f(bool): 0x1 -> 0x1 diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol index beff156f757a..ce6ff4fe2899 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol @@ -13,6 +13,8 @@ contract C { return 0; } } +// ==== +// compileViaYul: also // ---- // f(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE # We input longer data on purpose.# // g(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol index dc7c7f8905ab..073e015b4874 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol @@ -10,6 +10,7 @@ contract C { require(y == bytes2(0xffff)); } } - +// ==== +// compileViaYul: also // ---- // f() -> "\xff\xff\xff\xff" diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol index 5adc97378754..2ca882c9fa26 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol @@ -10,5 +10,7 @@ contract C { return 0; } } +// ==== +// compileViaYul: also // ---- // f(bytes2,uint16): "abc", 0x40102 -> FAILURE # We input longer data on purpose. # diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol index c1901c73839d..7cd496818fe9 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol @@ -8,6 +8,7 @@ contract C { return (x, y); } } - +// ==== +// compileViaYul: also // ---- // test() -> 0xff, 0xff diff --git a/test/libsolidity/semanticTests/constants/constant_string.sol b/test/libsolidity/semanticTests/constants/constant_string.sol index 56cbf982d120..6b588571d0c3 100644 --- a/test/libsolidity/semanticTests/constants/constant_string.sol +++ b/test/libsolidity/semanticTests/constants/constant_string.sol @@ -16,6 +16,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 3, "\x03\x01\x02" // g() -> 0x20, 3, "\x03\x01\x02" diff --git a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol index c05060b7e391..613cf62bb7db 100644 --- a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol +++ b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol @@ -6,5 +6,7 @@ contract Foo { uint256 constant x = 56; } +// ==== +// compileViaYul: also // ---- // getX() -> 56 diff --git a/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol index 2384c061f108..ffb98ada1bed 100644 --- a/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol +++ b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol @@ -20,5 +20,7 @@ contract Derived is Base { } } +// ==== +// compileViaYul: also // ---- // getA() -> 49 diff --git a/test/libsolidity/semanticTests/constructor/callvalue_check.sol b/test/libsolidity/semanticTests/constructor/callvalue_check.sol new file mode 100644 index 000000000000..c096382d0b77 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/callvalue_check.sol @@ -0,0 +1,41 @@ +contract A1 { constructor() public {} } +contract B1 is A1 {} + +contract A2 { constructor() public payable {} } +contract B2 is A2 {} + +contract B3 {} + +contract B4 { constructor() public {} } + +contract C { + function createWithValue(bytes memory c, uint256 value) public payable returns (bool) { + uint256 y = 0; + assembly { y := create(value, add(c, 0x20), mload(c)) } + return y != 0; + } + function f(uint256 value) public payable returns (bool) { + return createWithValue(type(B1).creationCode, value); + } + function g(uint256 value) public payable returns (bool) { + return createWithValue(type(B2).creationCode, value); + } + function h(uint256 value) public payable returns (bool) { + return createWithValue(type(B3).creationCode, value); + } + function i(uint256 value) public payable returns (bool) { + return createWithValue(type(B4).creationCode, value); + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// f(uint256), 2000 ether: 0 -> true +// f(uint256), 2000 ether: 100 -> false +// g(uint256), 2000 ether: 0 -> true +// g(uint256), 2000 ether: 100 -> false +// h(uint256), 2000 ether: 0 -> true +// h(uint256), 2000 ether: 100 -> false +// i(uint256), 2000 ether: 0 -> true +// i(uint256), 2000 ether: 100 -> false diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol index ec30bacf6c16..fe6a4c59b695 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol @@ -15,7 +15,8 @@ contract Main { return flag; } } - +// ==== +// compileViaYul: also // ---- // constructor(): "abc", true // getFlag() -> true diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol index 756478e342d0..b294980833e6 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol @@ -33,6 +33,8 @@ contract Main { } } +// ==== +// compileViaYul: also // ---- // getFlag() -> true // getName() -> "abc" diff --git a/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol index 2192dabf32bc..4517c9702334 100644 --- a/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol +++ b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol @@ -14,6 +14,8 @@ contract B { } } +// ==== +// compileViaYul: also // ---- // testIt() -> // test() -> 2 diff --git a/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol index e92a37b19583..6f2f414289fe 100644 --- a/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol +++ b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol @@ -20,5 +20,7 @@ contract Derived is Base { } } +// ==== +// compileViaYul: also // ---- // getA() -> 2 diff --git a/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol index 0aea44e6a493..1e8f9bc78142 100644 --- a/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol +++ b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol @@ -14,7 +14,8 @@ contract Derived is Base { return m_derived; } } - +// ==== +// compileViaYul: also // ---- // getBMember() -> 5 // getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol new file mode 100644 index 000000000000..9744aa3ceb7e --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol @@ -0,0 +1,21 @@ +contract A1 {} +contract B1 is A1 { constructor() public payable {} } + +contract A2 { constructor() public {} } +contract B2 is A2 { constructor() public payable {} } + +contract B3 { constructor() public payable {} } + +contract C { + function f() public payable returns (bool) { + // Make sure none of these revert. + new B1{value: 10}(); + new B2{value: 10}(); + new B3{value: 10}(); + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// f(), 2000 ether -> true diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol index df07364b368d..4f3828f3a976 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol @@ -5,6 +5,8 @@ contract test { return cond ? x : y; } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 0xcd // f(bool): false -> 0xabab diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol index 3915c7b8dc61..456b1902c915 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol @@ -3,5 +3,7 @@ contract test { return false ? 5 : 10; } } +// ==== +// compileViaYul: also // ---- // f() -> 10 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol index bff9122b1ea1..482849648267 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol @@ -7,6 +7,8 @@ contract test { return z(); } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol index 2a9d6de8086a..c8a335384d12 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol @@ -6,6 +6,8 @@ contract test { x > 50 ? 50 : 10; } } +// ==== +// compileViaYul: also // ---- // f(uint256): 1001 -> 1000 // f(uint256): 500 -> 100 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol index 06247f0dc535..65145507978a 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol @@ -3,5 +3,7 @@ contract test { return true ? 5 : 10; } } +// ==== +// compileViaYul: also // ---- // f() -> 5 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol index d27d06bacb79..53eba3f1d3ef 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol @@ -3,6 +3,8 @@ contract test { return cond ? (1, 2) : (3, 4); } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1, 2 // f(bool): false -> 3, 4 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol index bbaf051bde11..df6cdb3442b9 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol @@ -3,6 +3,8 @@ contract test { cond ? a = v : b = v; } } +// ==== +// compileViaYul: also // ---- // f(bool,uint256): true, 20 -> 20, 0 // f(bool,uint256): false, 20 -> 0, 20 diff --git a/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol b/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol index 9b5319ae0013..90efa8fdae1e 100644 --- a/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol +++ b/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol @@ -5,6 +5,8 @@ contract C { receive () payable external { ++y; } function f() external returns (uint, uint) { return (x, y); } } +// ==== +// compileViaYul: also // ---- // f() -> 0, 0 // () -> diff --git a/test/libsolidity/semanticTests/fallback/inherited.sol b/test/libsolidity/semanticTests/fallback/inherited.sol index a4ee55419cb9..1e0cdc40778c 100644 --- a/test/libsolidity/semanticTests/fallback/inherited.sol +++ b/test/libsolidity/semanticTests/fallback/inherited.sol @@ -4,6 +4,8 @@ contract A { function getData() public returns (uint r) { return data; } } contract B is A {} +// ==== +// compileViaYul: also // ---- // getData() -> 0 // (): 42 -> diff --git a/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol b/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol index dd97f4c03488..57dbb37bbd1a 100644 --- a/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol +++ b/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol @@ -4,6 +4,8 @@ contract A { function fow() public { x = 3; } fallback () external { x = 2; } } +// ==== +// compileViaYul: also // ---- // (): hex"d88e0b" // x() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol b/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol index 4dbfe91f107f..52ddfff98e78 100644 --- a/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol +++ b/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol @@ -22,6 +22,8 @@ contract test { return sum; } } +// ==== +// compileViaYul: also // ---- // f(uint256[]): 32, 3, 1000, 1, 2 -> 3 // f(uint256[]): 32, 3, 100, 500, 300 -> 600 diff --git a/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol b/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol index 3041f0e4b7f8..862f37f8d02f 100644 --- a/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol +++ b/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol @@ -10,5 +10,7 @@ contract C is V { function a() internal view override returns (uint256) { return 42;} } +// ==== +// compileViaYul: also // ---- // b() -> 42 diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol index e1cab8fe8af4..c074d8598689 100644 --- a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol @@ -11,7 +11,8 @@ contract C { return 7; } } - +// ==== +// compileViaYul: also // ---- // intern() -> FAILURE # This should throw exceptions # // extern() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol index 26a2a79f4c5c..44af5be40928 100644 --- a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol @@ -15,6 +15,7 @@ contract C { return 2; } } - +// ==== +// compileViaYul: also // ---- // t() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol index ffa22b8a27ea..0a80a9f5c7bf 100644 --- a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol +++ b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol @@ -22,6 +22,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // ---- // get() -> 0x00 diff --git a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol index 498449d17d1b..00f1f8a77753 100644 --- a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol +++ b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol @@ -24,6 +24,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: 0x00 diff --git a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol index 54baa45725fa..4fcc640f6ddd 100644 --- a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol +++ b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol @@ -16,6 +16,8 @@ contract test { return (a[0][key], a[1][key], b[0][key], b[1][key]); } } +// ==== +// compileViaYul: also // ---- // set(uint8,uint8,uint8,uint8,uint8): 1, 21, 22, 42, 43 -> 0, 0, 0, 0 // get(uint8): 1 -> 21, 22, 42, 43 diff --git a/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol b/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol index 728be2c09c7c..4154baa9b9bc 100644 --- a/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol +++ b/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol @@ -14,6 +14,8 @@ contract test { return (a[key], b[key]); } } +// ==== +// compileViaYul: also // ---- // set(uint8,uint8,uint8): 1, 21, 42 -> 0, 0 // get(uint8): 1 -> 21, 42 diff --git a/test/libsolidity/semanticTests/functionCall/multiple_functions.sol b/test/libsolidity/semanticTests/functionCall/multiple_functions.sol index 3c60a13f11cf..e72922d7b144 100644 --- a/test/libsolidity/semanticTests/functionCall/multiple_functions.sol +++ b/test/libsolidity/semanticTests/functionCall/multiple_functions.sol @@ -6,6 +6,7 @@ contract test { } // ==== // allowNonExistingFunctions: true +// compileViaYul: also // ---- // a() -> 0 // b() -> 1 diff --git a/test/libsolidity/semanticTests/functionCall/named_args.sol b/test/libsolidity/semanticTests/functionCall/named_args.sol index 132139b9918f..e959eba44c95 100644 --- a/test/libsolidity/semanticTests/functionCall/named_args.sol +++ b/test/libsolidity/semanticTests/functionCall/named_args.sol @@ -2,5 +2,7 @@ contract test { function a(uint a, uint b, uint c) public returns (uint r) { r = a * 100 + b * 10 + c * 1; } function b() public returns (uint r) { r = a({a: 1, b: 2, c: 3}); } } +// ==== +// compileViaYul: also // ---- // b() -> 123 diff --git a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol index e0c6ff5e03aa..07f6ff51d743 100644 --- a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol +++ b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol @@ -14,6 +14,8 @@ contract Main { } } +// ==== +// compileViaYul: also // ---- // constructor(), 20 wei -> // s() -> true diff --git a/test/libsolidity/semanticTests/functionCall/transaction_status.sol b/test/libsolidity/semanticTests/functionCall/transaction_status.sol index 6651630d5d39..449ebacbe70f 100644 --- a/test/libsolidity/semanticTests/functionCall/transaction_status.sol +++ b/test/libsolidity/semanticTests/functionCall/transaction_status.sol @@ -3,6 +3,8 @@ contract test { function g() public { revert(); } function h() public { assert(false); } } +// ==== +// compileViaYul: also // ---- // f() -> // g() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/value_test.sol b/test/libsolidity/semanticTests/functionCall/value_test.sol index 582cda9f6d91..9cd1fd9ef925 100644 --- a/test/libsolidity/semanticTests/functionCall/value_test.sol +++ b/test/libsolidity/semanticTests/functionCall/value_test.sol @@ -3,6 +3,8 @@ contract C { return msg.value; } } +// ==== +// compileViaYul: also // ---- // f(), 1 ether -> 1000000000000000000 // f(), 1 wei -> 1 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol index ebef9a2549a8..2cb6428f7a4b 100644 --- a/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol @@ -16,6 +16,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 7 -> 8 // f2(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol index 6fb4f5f6e439..0acbcc5858d9 100644 --- a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol @@ -7,10 +7,9 @@ contract C { return x(a); } - function g(uint256 x) public returns (uint256) { + function g(uint256 x) public pure returns (uint256) { return x + 1; } } - // ---- // f(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol index a79cb2d76ff3..d829c1554263 100644 --- a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol +++ b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol @@ -13,7 +13,8 @@ contract C { return double(_arg); } } - +// ==== +// compileViaYul: also // ---- // runtime(uint256): 3 -> 6 // initial() -> 4 diff --git a/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol b/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol index 3f71a31e0fe0..030a3544cc42 100644 --- a/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol +++ b/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol @@ -4,5 +4,7 @@ contract A { return a; } } +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/immutable/getter.sol b/test/libsolidity/semanticTests/immutable/getter.sol index bb4b191cf9f6..c0997744ed00 100644 --- a/test/libsolidity/semanticTests/immutable/getter.sol +++ b/test/libsolidity/semanticTests/immutable/getter.sol @@ -1,5 +1,7 @@ contract C { uint immutable public x = 1; } +// ==== +// compileViaYul: also // ---- // x() -> 1 diff --git a/test/libsolidity/semanticTests/immutable/inheritance.sol b/test/libsolidity/semanticTests/immutable/inheritance.sol index f61009f60040..bca0ee8895cd 100644 --- a/test/libsolidity/semanticTests/immutable/inheritance.sol +++ b/test/libsolidity/semanticTests/immutable/inheritance.sol @@ -26,5 +26,7 @@ contract D is B, C { return (a, b, c, d); } } +// ==== +// compileViaYul: also // ---- // f() -> 4, 3, 2, 1 diff --git a/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol b/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol index 0673aafb5672..0119a90a2e22 100644 --- a/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol +++ b/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol @@ -10,6 +10,8 @@ contract C { return z(); } } +// ==== +// compileViaYul: also // ---- // f() -> 7 // callZ() -> 7 diff --git a/test/libsolidity/semanticTests/immutable/multi_creation.sol b/test/libsolidity/semanticTests/immutable/multi_creation.sol index b9e362dbd5ce..970ea9155aa8 100644 --- a/test/libsolidity/semanticTests/immutable/multi_creation.sol +++ b/test/libsolidity/semanticTests/immutable/multi_creation.sol @@ -25,6 +25,8 @@ contract C { return (a, (new A()).f(), (new B()).f()); } } +// ==== +// compileViaYul: also // ---- // f() -> 3, 7, 5 // x() -> 7 diff --git a/test/libsolidity/semanticTests/immutable/stub.sol b/test/libsolidity/semanticTests/immutable/stub.sol index 387541066e56..a800ab90407a 100644 --- a/test/libsolidity/semanticTests/immutable/stub.sol +++ b/test/libsolidity/semanticTests/immutable/stub.sol @@ -9,5 +9,7 @@ contract C { return (x+x,y); } } +// ==== +// compileViaYul: also // ---- // f() -> 84, 23 diff --git a/test/libsolidity/semanticTests/immutable/use_scratch.sol b/test/libsolidity/semanticTests/immutable/use_scratch.sol index d83da476d423..442ef56360c4 100644 --- a/test/libsolidity/semanticTests/immutable/use_scratch.sol +++ b/test/libsolidity/semanticTests/immutable/use_scratch.sol @@ -13,6 +13,8 @@ contract C { return (x+x,y); } } +// ==== +// compileViaYul: also // ---- // constructor(): 3 -> // f() -> 84, 23 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol index 823afe2bdac6..8e42595d4cad 100644 --- a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol @@ -16,7 +16,8 @@ contract C { return true; } } - +// ==== +// compileViaYul: also // ---- // f() -> true // z() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol index ce56dbaa1965..8f48f2f52181 100644 --- a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol @@ -17,7 +17,8 @@ contract C { return true; } } - +// ==== +// compileViaYul: also // ---- // f() -> true // z() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/leave.sol b/test/libsolidity/semanticTests/inlineAssembly/leave.sol index 40add273e000..b8c0ccda2a1f 100644 --- a/test/libsolidity/semanticTests/inlineAssembly/leave.sol +++ b/test/libsolidity/semanticTests/inlineAssembly/leave.sol @@ -10,5 +10,7 @@ contract C { } } } +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/integer/basic.sol b/test/libsolidity/semanticTests/integer/basic.sol new file mode 100644 index 000000000000..7c31e3888594 --- /dev/null +++ b/test/libsolidity/semanticTests/integer/basic.sol @@ -0,0 +1,24 @@ +contract C { + function basic() public pure returns(bool) { + uint uint_min = type(uint).min; + require(uint_min == 0); + + uint uint_max = type(uint).max; + require(uint_max == 2**256 - 1); + require(uint_max == 115792089237316195423570985008687907853269984665640564039457584007913129639935); + + int int_min = type(int).min; + require(int_min == -2**255); + require(int_min == -57896044618658097711785492504343953926634992332820282019728792003956564819968); + + int int_max = type(int).max; + require(int_max == 2**255 -1); + require(int_max == 57896044618658097711785492504343953926634992332820282019728792003956564819967); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// basic() -> true diff --git a/test/libsolidity/semanticTests/integer/int.sol b/test/libsolidity/semanticTests/integer/int.sol new file mode 100644 index 000000000000..79d685645fb2 --- /dev/null +++ b/test/libsolidity/semanticTests/integer/int.sol @@ -0,0 +1,245 @@ +contract test { + + function intMinA() public pure returns (bool) { + + int8 int8_min = type(int8).min; + require(int8_min == -2**7); + + int16 int16_min = type(int16).min; + require(int16_min == -2**15); + + int24 int24_min = type(int24).min; + require(int24_min == -2**23); + + int32 int32_min = type(int32).min; + require(int32_min == -2**31); + + int40 int40_min = type(int40).min; + require(int40_min == -2**39); + + int48 int48_min = type(int48).min; + require(int48_min == -2**47); + + int56 int56_min = type(int56).min; + require(int56_min == -2**55); + + int64 int64_min = type(int64).min; + require(int64_min == -2**63); + + return true; + } + + function intMinB() public pure returns(bool) { + + int72 int72_min = type(int72).min; + require(int72_min == -2**71); + + int80 int80_min = type(int80).min; + require(int80_min == -2**79); + + int88 int88_min = type(int88).min; + require(int88_min == -2**87); + + int96 int96_min = type(int96).min; + require(int96_min == -2**95); + + int104 int104_min = type(int104).min; + require(int104_min == -2**103); + + int112 int112_min = type(int112).min; + require(int112_min == -2**111); + + int120 int120_min = type(int120).min; + require(int120_min == -2**119); + + int128 int128_min = type(int128).min; + require(int128_min == -2**127); + + return true; + } + + function intMinC() public pure returns (bool) { + + int136 int136_min = type(int136).min; + require(int136_min == -2**135); + + int144 int144_min = type(int144).min; + require(int144_min == -2**143); + + int152 int152_min = type(int152).min; + require(int152_min == -2**151); + + int160 int160_min = type(int160).min; + require(int160_min == -2**159); + + int168 int168_min = type(int168).min; + require(int168_min == -2**167); + + int176 int176_min = type(int176).min; + require(int176_min == -2**175); + + int184 int184_min = type(int184).min; + require(int184_min == -2**183); + + int192 int192_min = type(int192).min; + require(int192_min == -2**191); + + return true; + } + + function intMinD() public pure returns(bool) { + + int200 int200_min = type(int200).min; + require(int200_min == -2**199); + + int208 int208_min = type(int208).min; + require(int208_min == -2**207); + + int216 int216_min = type(int216).min; + require(int216_min == -2**215); + + int224 int224_min = type(int224).min; + require(int224_min == -2**223); + + int232 int232_min = type(int232).min; + require(int232_min == -2**231); + + int240 int240_min = type(int240).min; + require(int240_min == -2**239); + + int248 int248_min = type(int248).min; + require(int248_min == -2**247); + + int256 int256_min = type(int256).min; + require(int256_min == -2**255); + + return true; + } + + function intMaxA() public pure returns (bool) { + + int8 int8_max = type(int8).max; + require(int8_max == 2**7-1); + + int16 int16_max = type(int16).max; + require(int16_max == 2**15-1); + + int24 int24_max = type(int24).max; + require(int24_max == 2**23-1); + + int32 int32_max = type(int32).max; + require(int32_max == 2**31-1); + + int40 int40_max = type(int40).max; + require(int40_max == 2**39-1); + + int48 int48_max = type(int48).max; + require(int48_max == 2**47-1); + + int56 int56_max = type(int56).max; + require(int56_max == 2**55-1); + + int64 int64_max = type(int64).max; + require(int64_max == 2**63-1); + + return true; + } + + function intMaxB() public pure returns(bool) { + + int72 int72_max = type(int72).max; + require(int72_max == 2**71-1); + + int80 int80_max = type(int80).max; + require(int80_max == 2**79-1); + + int88 int88_max = type(int88).max; + require(int88_max == 2**87-1); + + int96 int96_max = type(int96).max; + require(int96_max == 2**95-1); + + int104 int104_max = type(int104).max; + require(int104_max == 2**103-1); + + int112 int112_max = type(int112).max; + require(int112_max == 2**111-1); + + int120 int120_max = type(int120).max; + require(int120_max == 2**119-1); + + int128 int128_max = type(int128).max; + require(int128_max == 2**127-1); + + return true; + } + + function intMaxC() public pure returns (bool) { + + int136 int136_max = type(int136).max; + require(int136_max == 2**135-1); + + int144 int144_max = type(int144).max; + require(int144_max == 2**143-1); + + int152 int152_max = type(int152).max; + require(int152_max == 2**151-1); + + int160 int160_max = type(int160).max; + require(int160_max == 2**159-1); + + int168 int168_max = type(int168).max; + require(int168_max == 2**167-1); + + int176 int176_max = type(int176).max; + require(int176_max == 2**175-1); + + int184 int184_max = type(int184).max; + require(int184_max == 2**183-1); + + int192 int192_max = type(int192).max; + require(int192_max == 2**191-1); + + return true; + } + + function intMaxD() public pure returns(bool) { + + int200 int200_max = type(int200).max; + require(int200_max == 2**199-1); + + int208 int208_max = type(int208).max; + require(int208_max == 2**207-1); + + int216 int216_max = type(int216).max; + require(int216_max == 2**215-1); + + int224 int224_max = type(int224).max; + require(int224_max == 2**223-1); + + int232 int232_max = type(int232).max; + require(int232_max == 2**231-1); + + int240 int240_max = type(int240).max; + require(int240_max == 2**239-1); + + int248 int248_max = type(int248).max; + require(int248_max == 2**247-1); + + int256 int256_max = type(int256).max; + require(int256_max == 2**255-1); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// intMinA() -> true +// intMinB() -> true +// intMinC() -> true +// intMinD() -> true +// intMaxA() -> true +// intMaxB() -> true +// intMaxC() -> true +// intMaxD() -> true diff --git a/test/libsolidity/semanticTests/integer/uint.sol b/test/libsolidity/semanticTests/integer/uint.sol new file mode 100644 index 000000000000..a2f3746c26a7 --- /dev/null +++ b/test/libsolidity/semanticTests/integer/uint.sol @@ -0,0 +1,244 @@ +contract test { + + function uintMinA() public pure returns(bool) { + + uint8 uint8_min = type(uint8).min; + require(uint8_min == 0); + + uint16 uint16_min = type(uint16).min; + require(uint16_min == 0); + + uint24 uint24_min = type(uint24).min; + require(uint24_min == 0); + + uint32 uint32_min = type(uint32).min; + require(uint32_min == 0); + + uint40 uint40_min = type(uint40).min; + require(uint40_min == 0); + + uint48 uint48_min = type(uint48).min; + require(uint48_min == 0); + + uint56 uint56_min = type(uint56).min; + require(uint56_min == 0); + + uint64 uint64_min = type(uint64).min; + require(uint64_min == 0); + + return true; + } + + function uintMinB() public pure returns(bool) { + + uint72 uint72_min = type(uint72).min; + require(uint72_min == 0); + + uint80 uint80_min = type(uint80).min; + require(uint80_min == 0); + + uint88 uint88_min = type(uint88).min; + require(uint88_min == 0); + + uint96 uint96_min = type(uint96).min; + require(uint96_min == 0); + + uint104 uint104_min = type(uint104).min; + require(uint104_min == 0); + + uint112 uint112_min = type(uint112).min; + require(uint112_min == 0); + + uint120 uint120_min = type(uint120).min; + require(uint120_min == 0); + + uint128 uint128_min = type(uint128).min; + require(uint128_min == 0); + + return true; + } + + function uintMinC() public pure returns(bool) { + + uint136 uint136_min = type(uint136).min; + require(uint136_min == 0); + + uint144 uint144_min = type(uint144).min; + require(uint144_min == 0); + + uint152 uint152_min = type(uint152).min; + require(uint152_min == 0); + + uint160 uint160_min = type(uint160).min; + require(uint160_min == 0); + + uint168 uint168_min = type(uint168).min; + require(uint168_min == 0); + + uint176 uint176_min = type(uint176).min; + require(uint176_min == 0); + + uint184 uint184_min = type(uint184).min; + require(uint184_min == 0); + + uint192 uint192_min = type(uint192).min; + require(uint192_min == 0); + + return true; + } + + function uintMinD() public pure returns(bool) { + + uint200 uint200_min = type(uint200).min; + require(uint200_min == 0); + + uint208 uint208_min = type(uint208).min; + require(uint208_min == 0); + + uint216 uint216_min = type(uint216).min; + require(uint216_min == 0); + + uint224 uint224_min = type(uint224).min; + require(uint224_min == 0); + + uint232 uint232_min = type(uint232).min; + require(uint232_min == 0); + + uint240 uint240_min = type(uint240).min; + require(uint240_min == 0); + + uint248 uint248_min = type(uint248).min; + require(uint248_min == 0); + + uint256 uint256_min = type(uint256).min; + require(uint256_min == 0); + + return true; + } + + function uintMaxA() public pure returns (bool) { + + uint8 uint8_max = type(uint8).max; + require(uint8_max == 2**8-1); + + uint16 uint16_max = type(uint16).max; + require(uint16_max == 2**16-1); + + uint24 uint24_max = type(uint24).max; + require(uint24_max == 2**24-1); + + uint32 uint32_max = type(uint32).max; + require(uint32_max == 2**32-1); + + uint40 uint40_max = type(uint40).max; + require(uint40_max == 2**40-1); + + uint48 uint48_max = type(uint48).max; + require(uint48_max == 2**48-1); + + uint56 uint56_max = type(uint56).max; + require(uint56_max == 2**56-1); + + uint64 uint64_max = type(uint64).max; + require(uint64_max == 2**64-1); + + return true; + } + + function uintMaxB() public pure returns (bool) { + + uint72 uint72_max = type(uint72).max; + require(uint72_max == 2**72-1); + + uint80 uint80_max = type(uint80).max; + require(uint80_max == 2**80-1); + + uint88 uint88_max = type(uint88).max; + require(uint88_max == 2**88-1); + + uint96 uint96_max = type(uint96).max; + require(uint96_max == 2**96-1); + + uint104 uint104_max = type(uint104).max; + require(uint104_max == 2**104-1); + + uint112 uint112_max = type(uint112).max; + require(uint112_max == 2**112-1); + + uint120 uint120_max = type(uint120).max; + require(uint120_max == 2**120-1); + + uint128 uint128_max = type(uint128).max; + require(uint128_max == 2**128-1); + + return true; + } + + function uintMaxC() public pure returns (bool) { + + uint136 uint136_max = type(uint136).max; + require(uint136_max == 2**136-1); + + uint144 uint144_max = type(uint144).max; + require(uint144_max == 2**144-1); + + uint152 uint152_max = type(uint152).max; + require(uint152_max == 2**152-1); + + uint160 uint160_max = type(uint160).max; + require(uint160_max == 2**160-1); + + uint168 uint168_max = type(uint168).max; + require(uint168_max == 2**168-1); + + uint176 uint176_max = type(uint176).max; + require(uint176_max == 2**176-1); + + uint184 uint184_max = type(uint184).max; + require(uint184_max == 2**184-1); + + uint192 uint192_max = type(uint192).max; + require(uint192_max == 2**192-1); + + return true; + } + + function uintMaxD() public pure returns(bool) { + uint200 uint200_max = type(uint200).max; + require(uint200_max == 2**200-1); + + uint208 uint208_max = type(uint208).max; + require(uint208_max == 2**208-1); + + uint216 uint216_max = type(uint216).max; + require(uint216_max == 2**216-1); + + uint224 uint224_max = type(uint224).max; + require(uint224_max == 2**224-1); + + uint232 uint232_max = type(uint232).max; + require(uint232_max == 2**232-1); + + uint240 uint240_max = type(uint240).max; + require(uint240_max == 2**240-1); + + uint248 uint248_max = type(uint248).max; + require(uint248_max == 2**248-1); + + uint256 uint256_max = type(uint256).max; + require(uint256_max == 2**256-1); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// uintMinA() -> true +// uintMinB() -> true +// uintMinC() -> true +// uintMinD() -> true +// uintMaxA() -> true +// uintMaxB() -> true +// uintMaxC() -> true +// uintMaxD() -> true diff --git a/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol b/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol index d2fa2e821e59..855ca4d40e9d 100644 --- a/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol +++ b/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol @@ -29,6 +29,8 @@ contract Homer is ERC165, Simpson { } } +// ==== +// compileViaYul: also // ---- // supportsInterface(bytes4): left(0x01ffc9a0) -> false // supportsInterface(bytes4): left(0x01ffc9a7) -> true diff --git a/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol b/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol index 9c9dd5eb7fc7..96f1a4742f53 100644 --- a/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol +++ b/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol @@ -40,6 +40,8 @@ contract Lisa is ERC165MappingImplementation, Simpson { } } +// ==== +// compileViaYul: also // ---- // supportsInterface(bytes4): left(0x01ffc9a0) -> false // supportsInterface(bytes4): left(0x01ffc9a7) -> true diff --git a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol index e25db0dcbbc1..ab7a097ccde6 100644 --- a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol +++ b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol @@ -9,5 +9,7 @@ contract B is A { } } +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol index 0fd02e8f3a9f..a9956cc80ff9 100644 --- a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol +++ b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol @@ -17,6 +17,7 @@ contract B is A { return A(this).f(m); } } - +// ==== +// compileViaYul: also // ---- // g() -> 23 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol index 26de9ce7087a..98922c389da9 100644 --- a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol @@ -14,5 +14,7 @@ contract Derived is Base { contract Final is Derived(4) {} +// ==== +// compileViaYul: also // ---- // m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol index 6349bd814ffd..cab918567e69 100644 --- a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol @@ -19,5 +19,7 @@ contract Derived is Base, Base1 { contract Final is Derived(4) {} +// ==== +// compileViaYul: also // ---- // m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol index 4556cf5c49eb..ab7bada38669 100644 --- a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol @@ -19,5 +19,7 @@ contract Derived is Base, Base1 { contract Final is Derived(4) {} +// ==== +// compileViaYul: also // ---- // m_i() -> 4 diff --git a/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol index f24d93c2d940..31a64ce20698 100644 --- a/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol +++ b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol @@ -10,5 +10,7 @@ contract Tsra { } } +// ==== +// compileViaYul: also // ---- // f() -> 1 diff --git a/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol index d7df52434136..9965a381581c 100644 --- a/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol +++ b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol @@ -13,5 +13,7 @@ contract Tsra { } } +// ==== +// compileViaYul: also // ---- // f() -> 1 diff --git a/test/libsolidity/semanticTests/literals/escape.sol b/test/libsolidity/semanticTests/literals/escape.sol new file mode 100644 index 000000000000..8f015297eb8f --- /dev/null +++ b/test/libsolidity/semanticTests/literals/escape.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +contract C +{ + function f() public pure returns (uint, byte, byte) { + bytes memory encoded = abi.encodePacked("\\\\"); + return (encoded.length, encoded[0], encoded[1]); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 2, 0x5c00000000000000000000000000000000000000000000000000000000000000, 0x5c00000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol b/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol index db7f70f83bdc..3194d7ee93ec 100644 --- a/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol +++ b/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol @@ -3,5 +3,7 @@ contract C { return hex"12_34_5678_9A"; } } +// ==== +// compileViaYul: also // ---- // f() -> 32, 5, left(0x123456789A) diff --git a/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol index 1d1036c2c8d2..27a9550cf1f8 100644 --- a/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol +++ b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol @@ -13,7 +13,8 @@ contract C { x = t; } } - +// ==== +// compileViaYul: also // ---- // x() -> 0 // f() -> diff --git a/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol index 1d1036c2c8d2..27a9550cf1f8 100644 --- a/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol +++ b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol @@ -13,7 +13,8 @@ contract C { x = t; } } - +// ==== +// compileViaYul: also // ---- // x() -> 0 // f() -> diff --git a/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol b/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol index ce04cd73745b..b6e9416a7fff 100644 --- a/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol +++ b/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol @@ -2,6 +2,8 @@ contract A { uint public x; receive () external payable { ++x; } } +// ==== +// compileViaYul: also // ---- // x() -> 0 // () diff --git a/test/libsolidity/semanticTests/receive/ether_and_data.sol b/test/libsolidity/semanticTests/receive/ether_and_data.sol index 4c48df8d47ad..44af7ab912b2 100644 --- a/test/libsolidity/semanticTests/receive/ether_and_data.sol +++ b/test/libsolidity/semanticTests/receive/ether_and_data.sol @@ -1,6 +1,8 @@ contract C { receive () payable external { } } +// ==== +// compileViaYul: also // ---- // (), 1 ether // (), 1 ether: 1 -> FAILURE diff --git a/test/libsolidity/semanticTests/receive/inherited.sol b/test/libsolidity/semanticTests/receive/inherited.sol index 36273068ac9b..a713229837d3 100644 --- a/test/libsolidity/semanticTests/receive/inherited.sol +++ b/test/libsolidity/semanticTests/receive/inherited.sol @@ -4,6 +4,8 @@ contract A { function getData() public returns (uint r) { return data; } } contract B is A {} +// ==== +// compileViaYul: also // ---- // getData() -> 0 // () -> diff --git a/test/libsolidity/semanticTests/revertStrings/array_slices.sol b/test/libsolidity/semanticTests/revertStrings/array_slices.sol index dec3e916d763..5d2cebb874bd 100644 --- a/test/libsolidity/semanticTests/revertStrings/array_slices.sol +++ b/test/libsolidity/semanticTests/revertStrings/array_slices.sol @@ -6,6 +6,7 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256,uint256,uint256[]): 2, 1, 0x80, 3, 1, 2, 3 -> FAILURE, hex"08c379a0", 0x20, 22, "Slice starts after end" // f(uint256,uint256,uint256[]): 1, 5, 0x80, 3, 1, 2, 3 -> FAILURE, hex"08c379a0", 0x20, 28, "Slice is greater than length" diff --git a/test/libsolidity/semanticTests/revertStrings/bubble.sol b/test/libsolidity/semanticTests/revertStrings/bubble.sol index 5e9a0730df5f..24eceaba3065 100644 --- a/test/libsolidity/semanticTests/revertStrings/bubble.sol +++ b/test/libsolidity/semanticTests/revertStrings/bubble.sol @@ -9,6 +9,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // revertStrings: debug // ---- diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol index 2538a2175f07..e91f08a03af2 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol @@ -7,5 +7,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 1 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray stride" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol index 9f9296d2a53a..d39b3f4fbb9e 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol @@ -8,5 +8,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][2][]): 0x20, 0x01, 0x20, 0x00 -> FAILURE, hex"08c379a0", 0x20, 28, "Invalid calldata tail offset" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol index 7aac0f7f8d26..0e2ba94b10da 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol @@ -10,5 +10,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00 -> FAILURE, hex"08c379a0", 0x20, 30, "Invalid calldata access offset" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol index 3b68bacea336..f54a47d731c8 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol @@ -7,5 +7,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 1, 0x20, 0x0100000000000000000000 -> FAILURE, hex"08c379a0", 0x20, 28, "Invalid calldata tail length" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol b/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol index 52809a0b2d8c..c19538d0a98e 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol @@ -7,5 +7,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256,uint256[],uint256): 6, 0x60, 9, 0x1000000000000000000000000000000000000000000000000000000000000002, 1, 2 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray length" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol b/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol index b6cc5800d42b..c3fcece1b749 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol @@ -5,5 +5,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 1, 0x20, 2, 0x42 -> FAILURE, hex"08c379a0", 0x20, 23, "Calldata tail too short" diff --git a/test/libsolidity/semanticTests/revertStrings/short_input_array.sol b/test/libsolidity/semanticTests/revertStrings/short_input_array.sol index 1a80acc26891..4c83b79ffa36 100644 --- a/test/libsolidity/semanticTests/revertStrings/short_input_array.sol +++ b/test/libsolidity/semanticTests/revertStrings/short_input_array.sol @@ -5,5 +5,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[]): 0x20, 1 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray stride" diff --git a/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol b/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol index f361da7b60d6..b8bb0493a358 100644 --- a/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol +++ b/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol @@ -5,5 +5,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // e(bytes): 0x20, 7 -> FAILURE, hex"08c379a0", 0x20, 39, "ABI decoding: invalid byte array", " length" diff --git a/test/libsolidity/semanticTests/revertStrings/transfer.sol b/test/libsolidity/semanticTests/revertStrings/transfer.sol index 0d766bd1edc2..5d13f7d72237 100644 --- a/test/libsolidity/semanticTests/revertStrings/transfer.sol +++ b/test/libsolidity/semanticTests/revertStrings/transfer.sol @@ -18,6 +18,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // revertStrings: debug // ---- diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol index d0adf2785d41..1d240813ae3c 100644 --- a/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol @@ -15,6 +15,7 @@ contract C { return this.tested(garbled); } } - +// ==== +// compileViaYul: also // ---- // test() -> FAILURE # should throw # diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol index 17ee32bb889e..3c082a363560 100644 --- a/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol @@ -22,7 +22,8 @@ contract C { return garbled != garbled; } } - +// ==== +// compileViaYul: also // ---- // test_eq_ok() -> 1 // test_eq() -> FAILURE # both should throw # diff --git a/test/libsolidity/semanticTests/reverts/revert.sol b/test/libsolidity/semanticTests/reverts/revert.sol index eae49c799bc6..02496ef9402c 100644 --- a/test/libsolidity/semanticTests/reverts/revert.sol +++ b/test/libsolidity/semanticTests/reverts/revert.sol @@ -14,6 +14,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> FAILURE // a() -> 42 diff --git a/test/libsolidity/semanticTests/reverts/simple_throw.sol b/test/libsolidity/semanticTests/reverts/simple_throw.sol index ad88deca6c0c..bf9df114c1d3 100644 --- a/test/libsolidity/semanticTests/reverts/simple_throw.sol +++ b/test/libsolidity/semanticTests/reverts/simple_throw.sol @@ -6,6 +6,8 @@ contract Test { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 11 -> 21 // f(uint256): 1 -> FAILURE diff --git a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol index f8b02693dae3..4e62acc5ed5a 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol @@ -18,6 +18,7 @@ contract A { } } // ==== +// compileViaYul: also // EVMVersion: >=constantinople // ---- // f(), 10 ether -> 3007, 3008, 3009 diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol index cc81c15e4df3..6789bc350261 100644 --- a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol +++ b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol @@ -7,5 +7,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol index 4c6f3737f654..4e43cae3787e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol @@ -1,6 +1,7 @@ contract C { uint256 public a = 0x42 << 8; } - +// ==== +// compileViaYul: also // ---- // a() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol index e5a4152b57b1..38a776b30739 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol index 766a8522e514..8278e045ce01 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol @@ -1,6 +1,7 @@ contract C { uint256 public a = 0x4200 >> 8; } - +// ==== +// compileViaYul: also // ---- // a() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol index 0f36c10ee0a3..1853814c6c53 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_left.sol b/test/libsolidity/semanticTests/shifts/shift_left.sol index 15d2a972a491..e72671cebd76 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol index 06cb386067be..fd5981996828 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol index 5cc15c1a85e3..2f470d50017e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint8): 0x4266, 0x0 -> 0x4266 // f(uint256,uint8): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol index 99ff376d6a63..de7b4ec3e0b2 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol @@ -6,6 +6,7 @@ contract C { return y << x; } } - +// ==== +// compileViaYul: also // ---- // f() -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol index 0f35077b15de..a08f13aef8b9 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint32,uint32): 0x4266, 0x0 -> 0x4266 // f(uint32,uint32): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol index 3070314f8454..af214a244d86 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x66, 0x0 -> 0x66 // f(uint8,uint8): 0x66, 0x8 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol index b92fb2229cf8..964b6543bfcb 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol @@ -1,6 +1,7 @@ contract C { int256 public a = -0x42 << 8; } - +// ==== +// compileViaYul: also // ---- // a() -> -16896 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol index b084633339b9..993fae441a13 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol @@ -1,6 +1,7 @@ contract C { int256 public a = -0x4200 >> 8; } - +// ==== +// compileViaYul: also // ---- // a() -> -66 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol index 77c18c44b1f2..61145824612f 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 1, -1 -> FAILURE // g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol index e63a9a57eafb..623a715ecf30 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol @@ -10,6 +10,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 1, -1 -> FAILURE // g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_overflow.sol b/test/libsolidity/semanticTests/shifts/shift_overflow.sol index f1b4bca0a920..54f5fcc2b67e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_overflow.sol +++ b/test/libsolidity/semanticTests/shifts/shift_overflow.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // leftU(uint8,uint8): 255, 8 -> 0 // leftU(uint8,uint8): 255, 1 -> 254 diff --git a/test/libsolidity/semanticTests/shifts/shift_right.sol b/test/libsolidity/semanticTests/shifts/shift_right.sol index d78d18abaeeb..bfdb665d1be4 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol index cfee67301925..80f25238c6cc 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol index ba819fbcedb2..5b84941674f9 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 0x4266, 0x0 -> 0x4266 // f(int256,int256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol index 0c1949a59dc3..4c705337c88d 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol @@ -18,6 +18,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe // f(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol index 54ac9540fc89..18ea9972c528 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol @@ -10,6 +10,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x00, 0x04 -> 0x0f // f(uint8,uint8): 0x00, 0x1004 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol index 73aae5bc906a..2bac06e6eb0d 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): -4266, 0 -> -4266 // f(int256,int256): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol index 7f3beb59f1a7..4fecffda4195 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): -4266, 0 -> -4266 // f(int256,int256): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol index 24ab541230ae..883f004d0efe 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int16,int16): -4266, 0 -> -4266 // f(int16,int16): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol index 7ff669dc9f08..4f689c01533c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int32,int32): -4266, 0 -> -4266 // f(int32,int32): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol index c6424f141e1b..02f293e3ca7a 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int8,int8): -66, 0 -> -66 // f(int8,int8): -66, 1 -> -33 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol index 6e462e704494..850a89be3c6f 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int16,int16): 0xff99, 0x00 -> FAILURE // f(int16,int16): 0xff99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol index 2466298f02ea..d797531ec425 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int32,int32): 0xffffff99, 0x00 -> FAILURE // f(int32,int32): 0xffffff99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol index 643bc5e62b77..ee485335d33e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int8,int8): 0x99, 0x00 -> FAILURE // f(int8,int8): 0x99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol index 03573d985c7d..8cc6c4a9871c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint32,uint32): 0x4266, 0x0 -> 0x4266 // f(uint32,uint32): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol index 8457b10e169b..acfd99b86953 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x66, 0x0 -> 0x66 // f(uint8,uint8): 0x66, 0x8 -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol b/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol new file mode 100644 index 000000000000..72b8f69c83c6 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint256 a, int8 b) public returns (uint256) { + assembly { b := 0xff } + return a << b; + } + function g(uint256 a, int8 b) public returns (uint256) { + assembly { b := 0xff } + return a >> b; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256,int8): 0x1234, 0x0 -> FAILURE +// g(uint256,int8): 0x1234, 0x0 -> FAILURE diff --git a/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol b/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol index db6f35497874..6bfc1da0aa89 100644 --- a/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol +++ b/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol @@ -12,6 +12,8 @@ contract C { return "any"; } } +// ==== +// compileViaYul: also // ---- // e(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB) // e(bytes): 32, 32, 0x20 -> 32, 32, 0x20 diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index e3bee950f076..27e26f1ebc66 100644 --- a/test/libsolidity/semanticTests/smoke/constructor.sol +++ b/test/libsolidity/semanticTests/smoke/constructor.sol @@ -10,6 +10,8 @@ contract C { state = _state; } } +// ==== +// compileViaYul: also // ---- // constructor(), 2 wei: 3 -> // state() -> 3 diff --git a/test/libsolidity/semanticTests/smoke/failure.sol b/test/libsolidity/semanticTests/smoke/failure.sol index e693a84596cf..95b8c9109e25 100644 --- a/test/libsolidity/semanticTests/smoke/failure.sol +++ b/test/libsolidity/semanticTests/smoke/failure.sol @@ -14,11 +14,12 @@ contract C { } } // ==== -// allowNonExistingFunctions: true +// compileViaYul: also // EVMVersion: >homestead +// allowNonExistingFunctions: true // ---- // _() -> FAILURE // e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed." // f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0 // g(bool): false -> FAILURE, hex"08c379a0", 0x20, 15, "Value is false." -// h() -> FAILURE \ No newline at end of file +// h() -> FAILURE diff --git a/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol b/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol index b255b1880b0e..5d18cf32d7c3 100644 --- a/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol +++ b/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol @@ -7,5 +7,7 @@ contract C { abi.decode; } } +// ==== +// compileViaYul: also // ---- // f() -> diff --git a/test/libsolidity/semanticTests/storage/complex_accessors.sol b/test/libsolidity/semanticTests/storage/complex_accessors.sol index 1169e4ea5ccb..9b3fa7a3c16d 100644 --- a/test/libsolidity/semanticTests/storage/complex_accessors.sol +++ b/test/libsolidity/semanticTests/storage/complex_accessors.sol @@ -10,6 +10,8 @@ contract test { to_multiple_map[42][23] = 31; } } +// ==== +// compileViaYul: also // ---- // to_string_map(uint256): 42 -> "24" // to_bool_map(uint256): 42 -> false diff --git a/test/libsolidity/semanticTests/storage/simple_accessor.sol b/test/libsolidity/semanticTests/storage/simple_accessor.sol index 23bcfbfac65c..aacfb93a06b8 100644 --- a/test/libsolidity/semanticTests/storage/simple_accessor.sol +++ b/test/libsolidity/semanticTests/storage/simple_accessor.sol @@ -4,5 +4,7 @@ contract test { data = 8; } } +// ==== +// compileViaYul: also // ---- // data() -> 8 diff --git a/test/libsolidity/semanticTests/tryCatch/assert.sol b/test/libsolidity/semanticTests/tryCatch/assert.sol index 8b6a7b99692e..be475a3f2ccf 100644 --- a/test/libsolidity/semanticTests/tryCatch/assert.sol +++ b/test/libsolidity/semanticTests/tryCatch/assert.sol @@ -11,6 +11,8 @@ contract C { } } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol b/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol index 2bfc23191f77..1b89213cf25f 100644 --- a/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol +++ b/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol @@ -149,6 +149,7 @@ contract C { } // ==== // EVMVersion: >=byzantium +// compileViaYul: also // ---- // f1() -> 2 // f1a() -> 2 diff --git a/test/libsolidity/semanticTests/tryCatch/trivial.sol b/test/libsolidity/semanticTests/tryCatch/trivial.sol index d43477e994ab..567b4b714679 100644 --- a/test/libsolidity/semanticTests/tryCatch/trivial.sol +++ b/test/libsolidity/semanticTests/tryCatch/trivial.sol @@ -11,6 +11,8 @@ contract C { } } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol b/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol index 8350628e4764..c7d2d8bf85ab 100644 --- a/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol +++ b/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol @@ -5,5 +5,7 @@ contract C { return (x, b); } } +// ==== +// compileViaYul: also // ---- // f(uint256): 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/types/external_function_to_address.sol b/test/libsolidity/semanticTests/types/external_function_to_address.sol index fb938d37aaca..8ae54485534f 100644 --- a/test/libsolidity/semanticTests/types/external_function_to_address.sol +++ b/test/libsolidity/semanticTests/types/external_function_to_address.sol @@ -6,6 +6,8 @@ contract C { return cb.address; } } +// ==== +// compileViaYul: also // ---- // f() -> true // g(function): hex"00000000000000000000000000000000000004226121ff00000000000000000" -> 0x42 diff --git a/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol b/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol index ee916a63d750..8e29ad63e3c3 100644 --- a/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol +++ b/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol @@ -8,6 +8,8 @@ contract test { return this.table(k); } } +// ==== +// compileViaYul: also // ---- // table(address): 0 -> 0 // table(address): 0x01 -> 0 diff --git a/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol b/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol index f1fd184eda90..f822a9395979 100644 --- a/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol +++ b/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol @@ -9,6 +9,8 @@ contract test { return this.table(k); } } +// ==== +// compileViaYul: also // ---- // table(uint8): 0 -> 0 // table(uint8): 0x01 -> 0 diff --git a/test/libsolidity/semanticTests/types/packing_signed_types.sol b/test/libsolidity/semanticTests/types/packing_signed_types.sol index 2d2e0e16e608..3a10fd336317 100644 --- a/test/libsolidity/semanticTests/types/packing_signed_types.sol +++ b/test/libsolidity/semanticTests/types/packing_signed_types.sol @@ -4,5 +4,7 @@ contract test { return int8(x); } } +// ==== +// compileViaYul: also // ---- // run() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa diff --git a/test/libsolidity/semanticTests/types/packing_unpacking_types.sol b/test/libsolidity/semanticTests/types/packing_unpacking_types.sol index 8b500cca1351..ea2ed58f2365 100644 --- a/test/libsolidity/semanticTests/types/packing_unpacking_types.sol +++ b/test/libsolidity/semanticTests/types/packing_unpacking_types.sol @@ -5,6 +5,8 @@ contract test { y = y * 0x10000000000000000 | ~c; } } +// ==== +// compileViaYul: also // ---- // run(bool,uint32,uint64): true, 0x0f0f0f0f, 0xf0f0f0f0f0f0f0f0 // -> 0x0000000000000000000000000000000000000001f0f0f0f00f0f0f0f0f0f0f0f diff --git a/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol b/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol index b9938582385a..b4b158f62316 100644 --- a/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol +++ b/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol @@ -11,5 +11,7 @@ contract test { return (m1[1], m1[2], m2[1], m2[2]); } } +// ==== +// compileViaYul: also // ---- // f() -> 42, 0, 0, 21 diff --git a/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol b/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol index df3ee2f547ba..5e237ae17655 100644 --- a/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol +++ b/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol @@ -10,5 +10,7 @@ contract test { return (m1[1], m1[2], m2[1], m2[2]); } } +// ==== +// compileViaYul: also // ---- // f() -> 42, 0, 0, 21 diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding.sol b/test/libsolidity/semanticTests/variables/public_state_overridding.sol index 2921f1a4af60..bff486eaaa91 100644 --- a/test/libsolidity/semanticTests/variables/public_state_overridding.sol +++ b/test/libsolidity/semanticTests/variables/public_state_overridding.sol @@ -11,8 +11,8 @@ contract X is A function set() public { test = 2; } } - - +// ==== +// compileViaYul: also // ---- // test() -> 0 // set() -> diff --git a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol index b83b1c598f84..4f849be89fbc 100644 --- a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol +++ b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol @@ -6,5 +6,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x57a diff --git a/test/libsolidity/semanticTests/various/code_access_create.sol b/test/libsolidity/semanticTests/various/code_access_create.sol index 3fbcf6132e6d..9029e59ec8b6 100644 --- a/test/libsolidity/semanticTests/various/code_access_create.sol +++ b/test/libsolidity/semanticTests/various/code_access_create.sol @@ -22,5 +22,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // test() -> 7 diff --git a/test/libsolidity/semanticTests/various/code_access_runtime.sol b/test/libsolidity/semanticTests/various/code_access_runtime.sol new file mode 100644 index 000000000000..cc1401c6f1bc --- /dev/null +++ b/test/libsolidity/semanticTests/various/code_access_runtime.sol @@ -0,0 +1,27 @@ +contract D { + uint256 x; + + constructor() public { + x = 7; + } + + function f() public view returns (uint256) { + return x; + } +} + + +contract C { + function test() public returns (uint256) { + D d = new D(); + bytes32 hash; + assembly { hash := extcodehash(d) } + assert(hash == keccak256(type(D).runtimeCode)); + return 42; + } +} + +// ==== +// EVMVersion: >=constantinople +// ---- +// test() -> 42 diff --git a/test/libsolidity/semanticTests/various/decayed_tuple.sol b/test/libsolidity/semanticTests/various/decayed_tuple.sol index b00942cb3225..2f1122f6a64d 100644 --- a/test/libsolidity/semanticTests/various/decayed_tuple.sol +++ b/test/libsolidity/semanticTests/various/decayed_tuple.sol @@ -5,6 +5,7 @@ contract C { return x; } } - +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/various/inline_member_init.sol b/test/libsolidity/semanticTests/various/inline_member_init.sol index 5dca66d80c07..cac10c786891 100644 --- a/test/libsolidity/semanticTests/various/inline_member_init.sol +++ b/test/libsolidity/semanticTests/various/inline_member_init.sol @@ -14,6 +14,7 @@ contract test { c = m_c; } } - +// ==== +// compileViaYul: also // ---- // get() -> 5, 6, 8 diff --git a/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol index 53f5b3718be7..7ee1028c9707 100644 --- a/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol +++ b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol @@ -18,7 +18,8 @@ contract Derived is Base { return m_derived; } } - +// ==== +// compileViaYul: also // ---- // getBMember() -> 5 // getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/various/literal_empty_string.sol b/test/libsolidity/semanticTests/various/literal_empty_string.sol index bf4da54099af..ab916ae8c170 100644 --- a/test/libsolidity/semanticTests/various/literal_empty_string.sol +++ b/test/libsolidity/semanticTests/various/literal_empty_string.sol @@ -12,6 +12,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // x() -> 0 // a() -> 0 diff --git a/test/libsolidity/semanticTests/various/multi_variable_declaration.sol b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol index 6f79442e7aff..75f3fa724efb 100644 --- a/test/libsolidity/semanticTests/various/multi_variable_declaration.sol +++ b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol @@ -42,6 +42,7 @@ contract C { return f1() && f2(); } } - +// ==== +// compileViaYul: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol index 9ba67b198b15..bc5e546caca0 100644 --- a/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol +++ b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol @@ -3,7 +3,8 @@ contract test { int8 public y = 127; int16 public q = 250; } - +// ==== +// compileViaYul: also // ---- // x() -> 2 // y() -> 127 diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol index 350ea2622142..a0231678f9fe 100644 --- a/test/libsolidity/semanticTests/various/skip_dynamic_types.sol +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol @@ -10,6 +10,7 @@ contract C { return (a, b); } } - +// ==== +// compileViaYul: also // ---- // g() -> 7, 8 diff --git a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol index a193e875204d..e9157e34cd31 100644 --- a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol +++ b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol @@ -32,6 +32,7 @@ contract D { } } // ==== +// compileViaYul: also // EVMVersion: 0x1 diff --git a/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol index 7a8a2c276218..d5f53c1205e1 100644 --- a/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol +++ b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol @@ -6,6 +6,7 @@ contract Test { return data["abc"]; } } - +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/various/string_tuples.sol b/test/libsolidity/semanticTests/various/string_tuples.sol index 3269d97c0b61..0a7a38b8b14c 100644 --- a/test/libsolidity/semanticTests/various/string_tuples.sol +++ b/test/libsolidity/semanticTests/various/string_tuples.sol @@ -11,7 +11,8 @@ contract C { return ("abc"); } } - +// ==== +// compileViaYul: also // ---- // f() -> 0x40, 0x8, 0x3, "abc" // g() -> 0x40, 0x80, 0x3, "abc", 0x3, "def" diff --git a/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol index 1f12ba390dd7..fae85cd34e8e 100644 --- a/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol +++ b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol @@ -5,6 +5,8 @@ contract test { return cond ? x : y; } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 0x1234ab // f(bool): false -> 0x1234abcd1234 diff --git a/test/libsolidity/semanticTests/various/tuples.sol b/test/libsolidity/semanticTests/various/tuples.sol index 00fcd6f9a08b..b89928a72c5e 100644 --- a/test/libsolidity/semanticTests/various/tuples.sol +++ b/test/libsolidity/semanticTests/various/tuples.sol @@ -25,6 +25,7 @@ contract C { if (a != 8 || b != 10) return 4; } } - +// ==== +// compileViaYul: also // ---- // f() -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol b/test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol new file mode 100644 index 000000000000..cc9e449382ff --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol @@ -0,0 +1,65 @@ +contract C { + function add() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 0; + assembly { x := 0x0101 } + return (x + y, y + x); + } + function sub() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 1; + assembly { x := 0x0101 } + return (x - y, y - x); + } + function mul() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 1; + assembly { x := 0x0101 } + return (x * y, y * x); + } + function div() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 1; + assembly { x := 0x0101 } + return (x / y, y / x); + } + function mod() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 2; + assembly { x := 0x0101 } + return (x % y, y % x); + } + function inc_pre() public pure returns (uint8) { + uint8 x; + assembly { x := 0x0100 } + return ++x; + } + function inc_post() public pure returns (uint8) { + uint8 x; + assembly { x := 0x0100 } + return x++; + } + function dec_pre() public pure returns (uint8) { + uint8 x; + assembly { x := not(0xFF) } + return --x; + } + function dec_post() public pure returns (uint8) { + uint8 x; + assembly { x := not(0xFF) } + return x--; + } + function neg() public pure returns (int8) { + int8 x; + assembly { x := 0x80 } + return -x; + } +} +// ==== +// compileViaYul: true +// ---- +// add() -> 1, 1 +// sub() -> 0, 0 +// mul() -> 1, 1 +// div() -> 1, 1 +// mod() -> 1, 0 +// inc_pre() -> 1 +// inc_post() -> 0 +// dec_pre() -> FAILURE +// dec_post() -> FAILURE +// neg() -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol b/test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol new file mode 100644 index 000000000000..86bd8ede7fd4 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol @@ -0,0 +1,41 @@ +contract C { + function eq() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x == y); + } + function neq() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x != y); + } + function geq() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x >= y); + } + function leq() public pure returns (bool) { + uint8 x = 2; uint8 y; + assembly { y := 0x0101 } + return (x <= y); + } + function gt() public pure returns (bool) { + uint8 x = 2; uint8 y; + assembly { y := 0x0101 } + return (x > y); + } + function lt() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x < y); + } +} +// ==== +// compileViaYul: also +// ---- +// eq() -> true +// neq() -> false +// geq() -> true +// leq() -> false +// gt() -> true +// lt() -> false diff --git a/test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol b/test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol new file mode 100644 index 000000000000..d03aa489f620 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol @@ -0,0 +1,15 @@ +contract C { + function f() public pure returns (uint8 x, bool a, bool b) { + uint8[1] memory m; + assembly { + mstore(m, 257) + } + x = m[0]; + a = (m[0] == 0x01); + b = (m[0] == 0x0101); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 1, true, false diff --git a/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol index 590294f15e33..e66b8ad4f6f1 100644 --- a/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol +++ b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol @@ -28,5 +28,7 @@ contract Derived is Base { } } +// ==== +// compileViaYul: also // ---- // getA() -> 2 diff --git a/test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol b/test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol new file mode 100644 index 000000000000..7b443949a668 --- /dev/null +++ b/test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol @@ -0,0 +1,8 @@ +contract c { + bytes public b; + function f() public { + b = msg.data[:]; + } +} +// ---- +// TypeError: (63-74): Type bytes calldata slice is not implicitly convertible to expected type bytes storage ref. diff --git a/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol b/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol index a31e5ab85abe..de90b0f75729 100644 --- a/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol +++ b/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol @@ -4,4 +4,3 @@ contract C { } } // ---- -// TypeError: (85-91): This type cannot be encoded. diff --git a/test/libsolidity/syntaxTests/constructor/nonpayable_new.sol b/test/libsolidity/syntaxTests/constructor/nonpayable_new.sol new file mode 100644 index 000000000000..c89508743f2b --- /dev/null +++ b/test/libsolidity/syntaxTests/constructor/nonpayable_new.sol @@ -0,0 +1,23 @@ +contract A1 { constructor() public {} } +contract B1 is A1 {} + +contract A2 { constructor() public payable {} } +contract B2 is A2 {} + +contract B3 {} + +contract B4 { constructor() public {} } + +contract C { + function f() public payable { + new B1{value: 10}(); + new B2{value: 10}(); + new B3{value: 10}(); + new B4{value: 10}(); + } +} +// ---- +// TypeError: (235-252): Cannot set option "value", since the constructor of contract B1 is not payable. +// TypeError: (258-275): Cannot set option "value", since the constructor of contract B2 is not payable. +// TypeError: (281-298): Cannot set option "value", since the constructor of contract B3 is not payable. +// TypeError: (304-321): Cannot set option "value", since the constructor of contract B4 is not payable. diff --git a/test/libsolidity/syntaxTests/constructor/payable_new.sol b/test/libsolidity/syntaxTests/constructor/payable_new.sol new file mode 100644 index 000000000000..fb8e9ef53bab --- /dev/null +++ b/test/libsolidity/syntaxTests/constructor/payable_new.sol @@ -0,0 +1,16 @@ +contract A1 {} +contract B1 is A1 { constructor() public payable {} } + +contract A2 { constructor() public {} } +contract B2 is A2 { constructor() public payable {} } + +contract B3 { constructor() public payable {} } + +contract C { + function f() public payable { + new B1{value: 10}(); + new B2{value: 10}(); + new B3{value: 10}(); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol b/test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol new file mode 100644 index 000000000000..163724d35f22 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol @@ -0,0 +1,7 @@ +contract C { + function f() public payable { + function() external payable x = this.f{value: 7}; + } +} +// ---- +// TypeError: (46-94): Type function () payable external is not implicitly convertible to expected type function () payable external. diff --git a/test/libsolidity/syntaxTests/immutable/creationCode.sol b/test/libsolidity/syntaxTests/immutable/creationCode.sol new file mode 100644 index 000000000000..aa747ba3e1f2 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/creationCode.sol @@ -0,0 +1,9 @@ +contract A { + address public immutable user = address(0x0); +} + +contract Test { + function test() public pure returns(bytes memory) { + return type(A).creationCode; + } +} diff --git a/test/libsolidity/syntaxTests/immutable/runtimeCode.sol b/test/libsolidity/syntaxTests/immutable/runtimeCode.sol new file mode 100644 index 000000000000..7db3245dc398 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/runtimeCode.sol @@ -0,0 +1,11 @@ +contract A { + address public immutable user = address(0x0); +} + +contract Test { + function test() public pure returns(bytes memory) { + return type(A).runtimeCode; + } +} +// ---- +// TypeError: (153-172): "runtimeCode" is not available for contracts containing immutable variables. diff --git a/test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol b/test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol new file mode 100644 index 000000000000..aec4acd2ef30 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol @@ -0,0 +1,13 @@ +contract Base { + address public immutable user = address(0x0); +} + +contract Derived is Base {} + +contract Test { + function test() public pure returns(bytes memory) { + return type(Derived).runtimeCode; + } +} +// ---- +// TypeError: (185-210): "runtimeCode" is not available for contracts containing immutable variables. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/immutables.sol b/test/libsolidity/syntaxTests/inlineAssembly/immutables.sol new file mode 100644 index 000000000000..17b30b8d8871 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/immutables.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + assembly { + setimmutable("abc", 0) + loadimmutable("abc") + } + } +} +// ---- +// DeclarationError: (63-75): Function not found. +// DeclarationError: (92-105): Function not found. diff --git a/test/libsolidity/syntaxTests/license/license_double.sol b/test/libsolidity/syntaxTests/license/license_double.sol new file mode 100644 index 000000000000..47d7eae1ba11 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0 +contract C {} +// SPDX-License-Identifier: MIT +// ---- +// ParserError: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_missing.sol b/test/libsolidity/syntaxTests/license/license_missing.sol new file mode 100644 index 000000000000..2dde0d2099a1 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_missing.sol @@ -0,0 +1 @@ +contract C {} diff --git a/test/libsolidity/syntaxTests/literalOperations/exponent.sol b/test/libsolidity/syntaxTests/literalOperations/exponent.sol new file mode 100644 index 000000000000..cee6263b7886 --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/exponent.sol @@ -0,0 +1,10 @@ +contract C { + function g() public pure { + int a; + a ** 1E1233; + a ** (1/2); + } +} +// ---- +// TypeError: (67-78): Operator ** not compatible with types int256 and int_const 1000...(1226 digits omitted)...0000. Exponent too large. +// TypeError: (88-98): Operator ** not compatible with types int256 and rational_const 1 / 2. Exponent is fractional. diff --git a/test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol b/test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol new file mode 100644 index 000000000000..56fed09ae6a7 --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + uint a; + a = a ** 1E5; + a = 0 ** 1E1233; + } +} diff --git a/test/libsolidity/syntaxTests/metaTypes/contract_min.sol b/test/libsolidity/syntaxTests/metaTypes/contract_min.sol new file mode 100644 index 000000000000..a922593b3905 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/contract_min.sol @@ -0,0 +1,7 @@ +contract Min { + function contractMin() public { + type(Min).min; + } +} +// ---- +// TypeError: (50-63): Member "min" not found or not visible after argument-dependent lookup in type(contract Min). diff --git a/test/libsolidity/syntaxTests/metaTypes/int_name.sol b/test/libsolidity/syntaxTests/metaTypes/int_name.sol new file mode 100644 index 000000000000..b6c4f49a5780 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/int_name.sol @@ -0,0 +1,7 @@ +contract test { + function intName() public { + type(int).name; + } +} +// ---- +// TypeError: (47-61): Member "name" not found or not visible after argument-dependent lookup in type(int256). diff --git a/test/libsolidity/syntaxTests/metaTypes/integer.sol b/test/libsolidity/syntaxTests/metaTypes/integer.sol new file mode 100644 index 000000000000..31bd069ec72b --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/integer.sol @@ -0,0 +1,12 @@ +contract Test { + function basic() public pure { + uint uintMax = type(uint).max; + uintMax; + int intMax = type(int).max; + intMax; + uint uintMin = type(uint).min; + uintMin; + int intMin = type(int).min; + intMin; + } +} diff --git a/test/libsolidity/syntaxTests/metaTypes/integer_err.sol b/test/libsolidity/syntaxTests/metaTypes/integer_err.sol new file mode 100644 index 000000000000..5a0610638bf8 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/integer_err.sol @@ -0,0 +1,15 @@ +contract Test { + function assignment() public { + uint8 uint8Min = type(int).min; + uint uintMin = type(int).min; + + if (type(int).min == 2**256 - 1) { + uintMin; + } + + } +} +// ---- +// TypeError: (59-89): Type int256 is not implicitly convertible to expected type uint8. +// TypeError: (99-127): Type int256 is not implicitly convertible to expected type uint256. +// TypeError: (142-169): Operator == not compatible with types int256 and int_const 1157...(70 digits omitted)...9935 diff --git a/test/libsolidity/syntaxTests/metaTypes/integer_pure.sol b/test/libsolidity/syntaxTests/metaTypes/integer_pure.sol new file mode 100644 index 000000000000..2eb115e0fd5f --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/integer_pure.sol @@ -0,0 +1,16 @@ +contract test { + + function viewAssignment() public view { + int min = type(int).min; + min; + } + + function assignment() public { + int max = type(int).max; + max; + } + +} +// ---- +// Warning: (21-112): Function state mutability can be restricted to pure +// Warning: (118-200): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol index 0ce06786ed7d..903338a432dd 100644 --- a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol +++ b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol @@ -4,5 +4,5 @@ contract Test { } } // ---- -// TypeError: (65-75): Invalid type for argument in function call. Contract type required, but type(contract Test) provided. -// TypeError: (60-76): Invalid type for argument in function call. Contract type required, but tuple() provided. +// TypeError: (65-75): Invalid type for argument in the function call. A contract type or an integer type is required, but type(contract Test) provided. +// TypeError: (60-76): Invalid type for argument in the function call. A contract type or an integer type is required, but tuple() provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol b/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol index 5c27d42f278c..94f498922f96 100644 --- a/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol +++ b/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol @@ -6,4 +6,4 @@ contract Test { } } // ---- -// TypeError: (154-155): Invalid type for argument in function call. Contract type required, but type(struct Test.S) provided. +// TypeError: (154-155): Invalid type for argument in the function call. A contract type or an integer type is required, but type(struct Test.S) provided. diff --git a/test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol b/test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol new file mode 100644 index 000000000000..c233cd69c66f --- /dev/null +++ b/test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.6.0; + +pragma experimental ABIEncoderV2; + +contract Ownable { + address private _owner; + + modifier onlyOwner() { + require(msg.sender == _owner, "Ownable: caller is not the owner"); + _; + } + + function renounceOwnership() public onlyOwner { } +} + +library VoteTiming { + function init(uint phaseLength) internal pure { + require(true, ""); + } +} + +contract Voting is Ownable { + constructor() public { + VoteTiming.init(1); + } +} +// ---- +// Warning: (324-340): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol index ba05fcb316af..aab8a183ac3e 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol @@ -3,5 +3,3 @@ contract test { } // ---- // DeclarationError: (31-55): The "constant" keyword can only be used for state variables. -// TypeError: (31-55): Constants of non-value type not yet implemented. -// TypeError: (31-55): Uninitialized "constant" variable. diff --git a/test/libsolidity/syntaxTests/parsing/array_range_nested.sol b/test/libsolidity/syntaxTests/parsing/array_range_nested.sol index 847d7596d8cb..16fde7999663 100644 --- a/test/libsolidity/syntaxTests/parsing/array_range_nested.sol +++ b/test/libsolidity/syntaxTests/parsing/array_range_nested.sol @@ -2,9 +2,8 @@ pragma experimental ABIEncoderV2; contract C { function f(uint256[][] calldata x) external pure { x[0][1:2]; - x[1:2][1:2]; - uint256 a = x[1:2][1:2][1:][3:][0][2]; - uint256 b = x[1:][3:4][1][1:][2:3][0]; + uint256 a = x[0][1:2][1:2][1:][3:][0]; + uint256 b = x[1][1:][3:4][1:][2:3][0]; a; b; } } diff --git a/test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol b/test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol new file mode 100644 index 000000000000..bc53d3fafaa2 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol @@ -0,0 +1,14 @@ +pragma experimental ABIEncoderV2; +contract C { + function f(uint256[][] calldata x) external pure { + x[1:2]; + x[:]; + x[1:]; + x[:2]; + } +} +// ---- +// TypeError: (110-116): Index range access is not supported for arrays with dynamically encoded base types. +// TypeError: (126-130): Index range access is not supported for arrays with dynamically encoded base types. +// TypeError: (140-145): Index range access is not supported for arrays with dynamically encoded base types. +// TypeError: (155-160): Index range access is not supported for arrays with dynamically encoded base types. diff --git a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol index bf78e59c6568..b9b1f97cd853 100644 --- a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol +++ b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol @@ -3,5 +3,3 @@ contract Foo { } // ---- // DeclarationError: (30-55): The "constant" keyword can only be used for state variables. -// TypeError: (30-55): Constants of non-value type not yet implemented. -// TypeError: (30-55): Uninitialized "constant" variable. diff --git a/test/libyul/ewasmTranslationTests/loop_break.yul b/test/libyul/ewasmTranslationTests/loop_break.yul new file mode 100644 index 000000000000..b473988d5fbb --- /dev/null +++ b/test/libyul/ewasmTranslationTests/loop_break.yul @@ -0,0 +1,13 @@ +{ + let i := 0 + for { } lt(i, 10) { i := add(i, 1) } { + if eq(i, 3) { break } + } + sstore(0, i) +} +// ---- +// Trace: +// Memory dump: +// 20: 0000000000000000000000000000000000000000000000000000000000000003 +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000003 diff --git a/test/libyul/ewasmTranslationTests/loop_continue.yul b/test/libyul/ewasmTranslationTests/loop_continue.yul new file mode 100644 index 000000000000..31200c2fe240 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/loop_continue.yul @@ -0,0 +1,22 @@ +{ + let i := 0 + for { } lt(i, 10) { i := add(i, 1) } { + if eq(i, 3) { continue } + sstore(add(i, 0x10), i) + } + sstore(0, i) +} +// ---- +// Trace: +// Memory dump: +// 20: 000000000000000000000000000000000000000000000000000000000000000a +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 000000000000000000000000000000000000000000000000000000000000000a +// 0000000000000000000000000000000000000000000000000000000000000011: 0000000000000000000000000000000000000000000000000000000000000001 +// 0000000000000000000000000000000000000000000000000000000000000012: 0000000000000000000000000000000000000000000000000000000000000002 +// 0000000000000000000000000000000000000000000000000000000000000014: 0000000000000000000000000000000000000000000000000000000000000004 +// 0000000000000000000000000000000000000000000000000000000000000015: 0000000000000000000000000000000000000000000000000000000000000005 +// 0000000000000000000000000000000000000000000000000000000000000016: 0000000000000000000000000000000000000000000000000000000000000006 +// 0000000000000000000000000000000000000000000000000000000000000017: 0000000000000000000000000000000000000000000000000000000000000007 +// 0000000000000000000000000000000000000000000000000000000000000018: 0000000000000000000000000000000000000000000000000000000000000008 +// 0000000000000000000000000000000000000000000000000000000000000019: 0000000000000000000000000000000000000000000000000000000000000009 diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index b8ae70a63195..28552a86ad45 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -69,6 +69,7 @@ bool IsolTestOptions::parse(int _argc, char const* const* _argv) std::cout << options << std::endl; return false; } + enforceViaYul = true; return res; } diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 7a3c63cff77c..846a544151f3 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -161,7 +161,11 @@ TestTool::Result TestTool::process() { (AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush(); - m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()}); + m_test = m_testCaseCreator(TestCase::Config{ + m_path.string(), + m_options.evmVersion(), + m_options.enforceViaYul + }); if (m_test->shouldRun()) switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted)) { @@ -232,7 +236,7 @@ TestTool::Request TestTool::handleResponse(bool _exception) cout << endl; ofstream file(m_path.string(), ios::trunc); m_test->printSource(file); - m_test->printSettings(file); + m_test->printUpdatedSettings(file); file << "// ----" << endl; m_test->printUpdatedExpectations(file, "// "); return Request::Rerun; diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt index 83543b9f0a4b..ccd71a983c82 100644 --- a/test/tools/ossfuzz/CMakeLists.txt +++ b/test/tools/ossfuzz/CMakeLists.txt @@ -10,7 +10,7 @@ add_dependencies(ossfuzz if (OSSFUZZ) add_custom_target(ossfuzz_proto) - add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz) + add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz sol_proto_ossfuzz) add_custom_target(ossfuzz_abiv2) add_dependencies(ossfuzz_abiv2 abiv2_proto_ossfuzz) @@ -78,6 +78,25 @@ if (OSSFUZZ) protobuf.a ) set_target_properties(abiv2_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) + + add_executable(sol_proto_ossfuzz + solProtoFuzzer.cpp + protoToSol.cpp + solProto.pb.cc + abiV2FuzzerCommon.cpp + ../../EVMHost.cpp + ) + target_include_directories(sol_proto_ossfuzz PRIVATE + /usr/include/libprotobuf-mutator + ) + target_link_libraries(sol_proto_ossfuzz PRIVATE solidity libsolc + evmc + evmone-standalone + protobuf-mutator-libfuzzer.a + protobuf-mutator.a + protobuf.a + ) + set_target_properties(sol_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) else() add_library(solc_opt_ossfuzz solc_opt_ossfuzz.cpp diff --git a/test/tools/ossfuzz/protoToSol.cpp b/test/tools/ossfuzz/protoToSol.cpp new file mode 100644 index 000000000000..aefbb41b9b5a --- /dev/null +++ b/test/tools/ossfuzz/protoToSol.cpp @@ -0,0 +1,228 @@ +/* + 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 . +*/ + +#include + +#include + +#include + +#include + +using namespace solidity::test::solprotofuzzer; +using namespace solidity::util; +using namespace std; + +string ProtoConverter::protoToSolidity(Program const& _p) +{ + // Create random number generator with fuzzer supplied + // seed. + m_randomGen = make_shared(_p.seed()); + return visit(_p); +} + +pair ProtoConverter::generateTestCase(TestContract const& _testContract) +{ + ostringstream testCode; + string usingLibDecl; + switch (_testContract.type()) + { + case TestContract::LIBRARY: + { + m_libraryTest = true; + auto testTuple = pseudoRandomLibraryTest(); + m_libraryName = get<0>(testTuple); + Whiskers u(R"(using for uint;)"); + u("ind", "\t"); + u("libraryName", get<0>(testTuple)); + usingLibDecl = u.render(); + Whiskers test(R"()"); + test("endl", "\n"); + test("ind", "\t\t"); + test("varDecl", "uint x;"); + Whiskers ifStmt(R"(if ()return 1;)"); + Whiskers ifCond(R"(x.() != )"); + ifCond("testFunction", get<1>(testTuple)); + ifCond("expectedOutput", get<2>(testTuple)); + ifStmt("cond", ifCond.render()); + ifStmt("endl", "\n"); + ifStmt("ind", "\t\t\t"); + test("ifStmt", ifStmt.render()); + break; + } + case TestContract::CONTRACT: + { + unsigned errorCode = 1; + unsigned contractVarIndex = 0; + for (auto const& testTuple: m_contractTests) + { + // Do this to avoid stack too deep errors + // We require uint as a return var, so we + // cannot have more than 16 variables without + // running into stack too deep errors + if (contractVarIndex >= s_maxVars) + break; + string contractName = testTuple.first; + string contractVarName = "tc" + to_string(contractVarIndex); + Whiskers init(R"( = new ();)"); + init("endl", "\n"); + init("ind", "\t\t"); + init("contractName", contractName); + init("contractVarName", contractVarName); + testCode << init.render(); + for (auto const& t: testTuple.second) + { + Whiskers tc(R"()"); + tc("endl", "\n"); + tc("ind", "\t\t"); + Whiskers ifStmt(R"(if ()return ;)"); + Whiskers ifCond(R"(.() != )"); + ifCond("contractVarName", contractVarName); + ifCond("testFunction", t.first); + ifCond("expectedOutput", t.second); + ifStmt("endl", "\n"); + ifStmt("cond", ifCond.render()); + ifStmt("ind", "\t\t\t"); + ifStmt("errorCode", to_string(errorCode)); + tc("ifStmt", ifStmt.render()); + testCode << tc.render(); + errorCode++; + } + contractVarIndex++; + } + break; + } + } + // Expected return value when all tests pass + testCode << Whiskers(R"(return 0;)")("endl", "\n")("ind", "\t\t").render(); + return {usingLibDecl, testCode.str()}; +} + +string ProtoConverter::visit(TestContract const& _testContract) +{ + string testCode; + string usingLibDecl; + m_libraryTest = false; + + // Simply return valid uint (zero) if there are + // no tests. + if (emptyLibraryTests() || emptyContractTests()) + testCode = Whiskers(R"(return 0;)")("endl", "\n")("ind", "\t\t").render(); + else + tie(usingLibDecl, testCode) = generateTestCase(_testContract); + + Whiskers c(R"(contract C {})"); + c("endl", "\n"); + c("isLibrary", m_libraryTest); + c("usingDecl", usingLibDecl); + Whiskers f("function test() public returns (uint){}"); + f("ind", "\t"); + f("endl", "\n"); + f("testCode", testCode); + c("function", f.render()); + return c.render(); +} + +bool ProtoConverter::libraryTest() const +{ + return m_libraryTest; +} + +string ProtoConverter::libraryName() const +{ + return m_libraryName; +} + +string ProtoConverter::visit(Program const& _p) +{ + ostringstream program; + ostringstream contracts; + + for (auto &contract: _p.contracts()) + contracts << visit(contract); + + Whiskers p(R"(pragma solidity >=0.0;)"); + p("endl", "\n"); + p("contracts", contracts.str()); + p("test", visit(_p.test())); + return p.render(); +} + +string ProtoConverter::visit(ContractType const& _contractType) +{ + switch (_contractType.contract_type_oneof_case()) + { + case ContractType::kC: + return visit(_contractType.c()); + case ContractType::kL: + return visit(_contractType.l()); + case ContractType::kI: + return visit(_contractType.i()); + case ContractType::CONTRACT_TYPE_ONEOF_NOT_SET: + return ""; + } +} + +string ProtoConverter::visit(Contract const& _contract) +{ + openProgramScope(&_contract); + return ""; +} + +string ProtoConverter::visit(Interface const& _interface) +{ + openProgramScope(&_interface); + return ""; +} + +string ProtoConverter::visit(Library const& _library) +{ + openProgramScope(&_library); + return ""; +} + +tuple ProtoConverter::pseudoRandomLibraryTest() +{ + solAssert(m_libraryTests.size() > 0, "Sol proto fuzzer: No library tests found"); + unsigned index = randomNumber() % m_libraryTests.size(); + return m_libraryTests[index]; +} + +void ProtoConverter::openProgramScope(CIL _program) +{ + string programNamePrefix; + if (holds_alternative(_program)) + programNamePrefix = "C"; + else if (holds_alternative(_program)) + programNamePrefix = "I"; + else + programNamePrefix = "L"; + string programName = programNamePrefix + to_string(m_programNumericSuffix++); + m_programNameMap.emplace(_program, programName); +} + +string ProtoConverter::programName(CIL _program) +{ + solAssert(m_programNameMap.count(_program), "Sol proto fuzzer: Unregistered program"); + return m_programNameMap[_program]; +} + +unsigned ProtoConverter::randomNumber() +{ + solAssert(m_randomGen, "Sol proto fuzzer: Uninitialized random number generator"); + return m_randomGen->operator()(); +} diff --git a/test/tools/ossfuzz/protoToSol.h b/test/tools/ossfuzz/protoToSol.h new file mode 100644 index 000000000000..de2220752210 --- /dev/null +++ b/test/tools/ossfuzz/protoToSol.h @@ -0,0 +1,185 @@ +/* + 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 . +*/ +#pragma once + +#include + +#include +#include +#include +#include + +namespace solidity::test::solprotofuzzer +{ +/// Random number generator that is seeded with a fuzzer +/// supplied unsigned integer. +struct SolRandomNumGenerator +{ + using RandomEngine = std::minstd_rand; + + explicit SolRandomNumGenerator(unsigned _seed): m_random(RandomEngine(_seed)) {} + + /// @returns a pseudo random unsigned integer + unsigned operator()() + { + return m_random(); + } + + RandomEngine m_random; +}; + +/* There are two types of tests created by the converter: + * - library test + * - contract test + * + * The template for library test is the following: + * + * // Library generated from fuzzer protobuf specification + * library L0 { + * function f0(uint) public view returns (uint) { + * return 31337; + * } + * function f1(uint) public pure returns (uint) { + * return 455; + * } + * } + * library L1 { + * function f0(uint) external view returns (uint) { + * return 607; + * } + * } + * + * // Test entry point + * contract C { + * // Uses a single pseudo randomly chosen library + * // and calls a pseudo randomly chosen function + * // returning a non-zero error code on failure or + * // a zero uint when test passes. + * using L0 for uint; + * function test() public pure returns (uint) { + * uint x; + * if (x.f1() != 455) + * return 1; + * return 0; + * } + * } + * + * The template for contract test is the following + * // Contracts generated from fuzzer protobuf specification + * contract C0B { + * function f0() public pure virtual returns (uint) + * { + * return 42; + * } + * } + * contract C0 is C0B { + * function f0() public pure override returns (uint) + * { + * return 1337; + * } + * } + * + * // Test entry point + * contract C { + * // Invokes one or more contract functions returning + * // a non-zero error code for failure, a zero uint + * // when all tests pass + * function test() public pure returns (uint) + * { + * C0 tc0 = new C0(); + * if (tc0.f0() != 1337) + * return 1; + * C0B tc1 = new C0B(); + * if (tc1.f0() != 42) + * return 2; + * // Expected return value if all tests pass + * return 0; + * } + * } + */ +class ProtoConverter +{ +public: + ProtoConverter() {} + ProtoConverter(ProtoConverter const&) = delete; + ProtoConverter(ProtoConverter&&) = delete; + std::string protoToSolidity(Program const&); + /// @returns true if test calls a library function, false + /// otherwise + bool libraryTest() const; + /// @returns name of the library under test + std::string libraryName() const; +private: + /// Variant type that points to one of contract, interface, library protobuf messages + using CIL = std::variant; + /// Protobuf message visitors that accept a const reference to a protobuf message + /// type and return its solidity translation. + std::string visit(Program const&); + std::string visit(TestContract const&); + std::string visit(ContractType const&); + std::string visit(Interface const& _interface); + std::string visit(Library const& _library); + std::string visit(Contract const& _contract); + /// @returns a string pair containing a library declaration (relevant for library + /// tests only) and a solidity test case + std::pair generateTestCase(TestContract const& _testContract); + /// @returns name of a program i.e., contract, library or interface + std::string programName(CIL _program); + /// @returns a tuple containing the names of the library and function under + /// test, and its expected output. + std::tuple pseudoRandomLibraryTest(); + /// Performs bookkeeping for a fuzzer-supplied program + void openProgramScope(CIL _program); + /// @returns a deterministic pseudo random unsigned integer + unsigned randomNumber(); + /// @returns true if fuzzer supplied Library protobuf message + /// contains zero functions, false otherwise. + static bool emptyLibrary(Library const& _library) + { + return _library.funcdef_size() == 0; + } + /// @returns true if there are no valid library test cases, false + /// otherwise. + bool emptyLibraryTests() + { + return m_libraryTests.empty(); + } + /// @returns true if there are no valid contract test cases, false + /// otherwise. + bool emptyContractTests() + { + return m_contractTests.empty(); + } + /// Numeric suffix that is part of program names e.g., "0" in "C0" + unsigned m_programNumericSuffix = 0; + /// Flag that states whether library call is tested (true) or not (false). + bool m_libraryTest = false; + /// A smart pointer to fuzzer driven random number generator + std::shared_ptr m_randomGen; + /// Maps protobuf program to its string name + std::map m_programNameMap; + /// List of tuples containing library name, function and its expected output + std::vector> m_libraryTests; + /// Maps contract name to a map of function names and their expected output + std::map> m_contractTests; + /// Name of the library under test, relevant if m_libraryTest is set + std::string m_libraryName; + /// Maximum number of local variables in test function to avoid stack too deep + /// errors + static unsigned constexpr s_maxVars = 15; +}; +} diff --git a/test/tools/ossfuzz/solProto.proto b/test/tools/ossfuzz/solProto.proto new file mode 100644 index 000000000000..86e938c7c806 --- /dev/null +++ b/test/tools/ossfuzz/solProto.proto @@ -0,0 +1,111 @@ +/* + 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 . +*/ + +syntax = "proto2"; + +message InterfaceFunction { + enum StateMutability { + PURE = 0; + VIEW = 1; + PAYABLE = 2; + NONPAYABLE = 3; + } + required StateMutability mut = 1; +} + +message LibraryFunction { + // Library functions cannot be payable + enum StateMutability { + PURE = 0; + VIEW = 1; + NONPAYABLE = 2; + } + enum Visibility { + PUBLIC = 0; + EXTERNAL = 1; + INTERNAL = 2; + PRIVATE = 3; + } + required Visibility vis = 1; + required StateMutability mut = 2; +} + +message ContractFunction { + enum StateMutability { + PURE = 0; + VIEW = 1; + PAYABLE = 2; + NONPAYABLE = 3; + } + enum Visibility { + PUBLIC = 0; + EXTERNAL = 1; + INTERNAL = 2; + PRIVATE = 3; + } + required Visibility vis = 1; + required StateMutability mut = 2; + required bool virtualfunc = 3; +} + +message Library { + repeated LibraryFunction funcdef = 1; +} + +message Interface { + repeated InterfaceFunction funcdef = 1; + repeated Interface bases = 2; +} + +message Contract { + repeated ContractFunction funcdef = 1; + required bool abstract = 2; + repeated ContractOrInterface bases = 3; +} + +message ContractOrInterface { + oneof contract_or_interface_oneof { + Contract c = 1; + Interface i = 2; + } +} + +message ContractType { + oneof contract_type_oneof { + Contract c = 1; + Library l = 2; + Interface i = 3; + } +} + +message TestContract { + enum Type { + LIBRARY = 0; + CONTRACT = 1; + } + required Type type = 1; +} + +message Program { + repeated ContractType contracts = 1; + required TestContract test = 2; + // Seed is an unsigned integer that initializes + // a pseudo random number generator. + required uint64 seed = 3; +} + +package solidity.test.solprotofuzzer; diff --git a/test/tools/ossfuzz/solProtoFuzzer.cpp b/test/tools/ossfuzz/solProtoFuzzer.cpp new file mode 100644 index 000000000000..80facb3e132f --- /dev/null +++ b/test/tools/ossfuzz/solProtoFuzzer.cpp @@ -0,0 +1,234 @@ +/* + 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 . +*/ + +#include +#include +#include +#include + +#include +#include + +#include + +static evmc::VM evmone = evmc::VM{evmc_create_evmone()}; + +using namespace solidity::test::abiv2fuzzer; +using namespace solidity::test::solprotofuzzer; +using namespace solidity; +using namespace solidity::test; +using namespace solidity::util; +using namespace std; + +namespace +{ +/// Test function returns a uint256 value +static size_t const expectedOutputLength = 32; +/// Expected output value is decimal 0 +static uint8_t const expectedOutput[expectedOutputLength] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/// Compares the contents of the memory address pointed to +/// by `_result` of `_length` bytes to the expected output. +/// Returns true if `_result` matches expected output, false +/// otherwise. +bool isOutputExpected(evmc::result const& _run) +{ + if (_run.output_size != expectedOutputLength) + return false; + + return memcmp(_run.output_data, expectedOutput, expectedOutputLength) == 0; +} + +/// Accepts a reference to a user-specified input and returns an +/// evmc_message with all of its fields zero initialized except +/// gas and input fields. +/// The gas field is set to the maximum permissible value so that we +/// don't run into out of gas errors. The input field is copied from +/// user input. +evmc_message initializeMessage(bytes const& _input) +{ + // Zero initialize all message fields + evmc_message msg = {}; + // Gas available (value of type int64_t) is set to its maximum + // value. + msg.gas = std::numeric_limits::max(); + msg.input_data = _input.data(); + msg.input_size = _input.size(); + return msg; +} + +/// Accepts host context implementation, and keccak256 hash of the function +/// to be called at a specified address in the simulated blockchain as +/// input and returns the result of the execution of the called function. +evmc::result executeContract( + EVMHost& _hostContext, + bytes const& _functionHash, + evmc_address _deployedAddress +) +{ + evmc_message message = initializeMessage(_functionHash); + message.destination = _deployedAddress; + message.kind = EVMC_CALL; + return _hostContext.call(message); +} + +/// Accepts a reference to host context implementation and byte code +/// as input and deploys it on the simulated blockchain. Returns the +/// result of deployment. +evmc::result deployContract(EVMHost& _hostContext, bytes const& _code) +{ + evmc_message message = initializeMessage(_code); + message.kind = EVMC_CREATE; + return _hostContext.call(message); +} + +std::pair compileContract( + std::string _sourceCode, + std::string _contractName, + std::map const& _libraryAddresses = {}, + frontend::OptimiserSettings _optimization = frontend::OptimiserSettings::minimal() +) +{ + try + { + // Compile contract generated by the proto fuzzer + SolidityCompilationFramework solCompilationFramework; + return std::make_pair( + solCompilationFramework.compileContract(_sourceCode, _contractName, _libraryAddresses, _optimization), + solCompilationFramework.getMethodIdentifiers() + ); + } + // Ignore stack too deep errors during compilation + catch (evmasm::StackTooDeepException const&) + { + return std::make_pair(bytes{}, Json::Value(0)); + } +} + +evmc::result deployAndExecute(EVMHost& _hostContext, bytes _byteCode, std::string _hexEncodedInput) +{ + // Deploy contract and signal failure if deploy failed + evmc::result createResult = deployContract(_hostContext, _byteCode); + solAssert( + createResult.status_code == EVMC_SUCCESS, + "Proto solc fuzzer: Contract creation failed" + ); + + // Execute test function and signal failure if EVM reverted or + // did not return expected output on successful execution. + evmc::result callResult = executeContract( + _hostContext, + fromHex(_hexEncodedInput), + createResult.create_address + ); + + // We don't care about EVM One failures other than EVMC_REVERT + solAssert(callResult.status_code != EVMC_REVERT, "Proto solc fuzzer: EVM One reverted"); + return callResult; +} + +evmc::result compileDeployAndExecute( + std::string _sourceCode, + std::string _contractName, + std::string _methodName, + frontend::OptimiserSettings _optimization, + std::string _libraryName = {} +) +{ + bytes libraryBytecode; + Json::Value libIds; + // We target the default EVM which is the latest + langutil::EVMVersion version = {}; + EVMHost hostContext(version, evmone); + std::map _libraryAddressMap; + + // First deploy library + if (!_libraryName.empty()) + { + tie(libraryBytecode, libIds) = compileContract( + _sourceCode, + _libraryName, + {}, + _optimization + ); + // Deploy contract and signal failure if deploy failed + evmc::result createResult = deployContract(hostContext, libraryBytecode); + solAssert( + createResult.status_code == EVMC_SUCCESS, + "Proto solc fuzzer: Library deployment failed" + ); + _libraryAddressMap[_libraryName] = EVMHost::convertFromEVMC(createResult.create_address); + } + + auto [bytecode, ids] = compileContract( + _sourceCode, + _contractName, + _libraryAddressMap, + _optimization + ); + + return deployAndExecute( + hostContext, + bytecode, + ids[_methodName].asString() + ); +} +} + +DEFINE_PROTO_FUZZER(Program const& _input) +{ + ProtoConverter converter; + string sol_source = converter.protoToSolidity(_input); + + if (char const* dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) + { + // With libFuzzer binary run this to generate a YUL source file x.yul: + // PROTO_FUZZER_DUMP_PATH=x.yul ./a.out proto-input + ofstream of(dump_path); + of.write(sol_source.data(), sol_source.size()); + } + + if (char const* dump_path = getenv("SOL_DEBUG_FILE")) + { + sol_source.clear(); + // With libFuzzer binary run this to generate a YUL source file x.yul: + // PROTO_FUZZER_LOAD_PATH=x.yul ./a.out proto-input + ifstream ifstr(dump_path); + sol_source = { + std::istreambuf_iterator(ifstr), + std::istreambuf_iterator() + }; + std::cout << sol_source << std::endl; + } + + auto minimalResult = compileDeployAndExecute( + sol_source, + ":C", + "test()", + frontend::OptimiserSettings::minimal(), + converter.libraryTest() ? converter.libraryName() : "" + ); + bool successState = minimalResult.status_code == EVMC_SUCCESS; + if (successState) + solAssert( + isOutputExpected(minimalResult), + "Proto solc fuzzer: Output incorrect" + ); +} diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index de074e642fa7..9f5d560852e5 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -61,7 +61,7 @@ class YulOpti public: void printErrors() { - SourceReferenceFormatter formatter(cout); + SourceReferenceFormatter formatter(cerr); for (auto const& error: m_errors) formatter.printErrorInformation(*error); @@ -74,7 +74,7 @@ class YulOpti m_ast = yul::Parser(errorReporter, m_dialect).parse(scanner, false); if (!m_ast || !errorReporter.errors().empty()) { - cout << "Error parsing source." << endl; + cerr << "Error parsing source." << endl; printErrors(); return false; } @@ -86,7 +86,7 @@ class YulOpti ); if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) { - cout << "Error analyzing source." << endl; + cerr << "Error analyzing source." << endl; printErrors(); return false; } @@ -119,7 +119,15 @@ class YulOpti for (auto const& optionAndDescription: _extraOptions) { - yulAssert(_optimizationSteps.count(optionAndDescription.first) == 0, ""); + yulAssert( + _optimizationSteps.count(optionAndDescription.first) == 0, + "ERROR: Conflict between yulopti controls and Yul optimizer step abbreviations.\n" + "Character '" + string(1, optionAndDescription.first) + "' is assigned to both " + + optionAndDescription.second + " and " + _optimizationSteps.at(optionAndDescription.first) + " step.\n" + "This is most likely caused by someone adding a new step abbreviation to " + "OptimiserSuite::stepNameToAbbreviationMap() and not realizing that it's used by yulopti.\n" + "Please update the code to use a different character and recompile yulopti." + ); printPair(optionAndDescription); } @@ -146,9 +154,9 @@ class YulOpti } map const& abbreviationMap = OptimiserSuite::stepAbbreviationToNameMap(); map const& extraOptions = { - {'q', "quit"}, - {'l', "VarNameCleaner"}, - {'p', "StackCompressor"}, + {'#', "quit"}, + {',', "VarNameCleaner"}, + {';', "StackCompressor"}, }; printUsageBanner(abbreviationMap, extraOptions, 4); @@ -167,14 +175,14 @@ class YulOpti } else switch (option) { - case 'q': + case '#': return; - case 'l': + case ',': VarNameCleaner::run(context, *m_ast); // VarNameCleaner destroys the unique names guarantee of the disambiguator. disambiguated = false; break; - case 'p': + case ';': { Object obj; obj.code = m_ast; @@ -182,7 +190,7 @@ class YulOpti break; } default: - cout << "Unknown option." << endl; + cerr << "Unknown option." << endl; } source = AsmPrinter{m_dialect}(*m_ast); } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 241a80f46e89..f6b87c9f6519 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -42,6 +42,6 @@ add_executable(yul-phaser yulPhaser/SimulationRNG.h yulPhaser/SimulationRNG.cpp ) -target_link_libraries(yul-phaser PRIVATE solidity Boost::program_options) +target_link_libraries(yul-phaser PRIVATE solidity Boost::filesystem Boost::program_options) install(TARGETS yul-phaser DESTINATION "${CMAKE_INSTALL_BINDIR}") diff --git a/tools/solidityUpgrade/SourceTransform.h b/tools/solidityUpgrade/SourceTransform.h index 2b42471c15f5..a33a1d97ed15 100644 --- a/tools/solidityUpgrade/SourceTransform.h +++ b/tools/solidityUpgrade/SourceTransform.h @@ -15,6 +15,8 @@ along with solidity. If not, see . */ +#pragma once + #include #include diff --git a/tools/yulPhaser/README.md b/tools/yulPhaser/README.md index abc2a0e47337..3bc72b5379df 100644 --- a/tools/yulPhaser/README.md +++ b/tools/yulPhaser/README.md @@ -9,7 +9,7 @@ The input is a set of one or more [Yul](/docs/yul.rst) programs and each sequenc Optimised programs are given numeric scores according to the selected metric. Optimisation step sequences are presented in an abbreviated form - as strings of letters where each character represents one step. -The abbreviations are defined in [`OptimiserSuite::stepNameToAbbreviationMap()`](/libyul/optimiser/Suite.cpp#L388-L423). +There's a [table listing available abbreviations in the optimiser docs](/docs/yul.rst#optimization-step-sequence). ### How to use it The application has sensible defaults for most parameters. @@ -66,14 +66,18 @@ tools/yul-phaser *.yul \ `yul-phaser` can process the intermediate representation produced by `solc`: ``` bash -solc/solc \ - --ir \ - --no-optimize-yul \ - --output-dir +solc/solc --ir --output-dir ``` After running this command you'll find one or more .yul files in the output directory. -These files contain whole Yul objects rather than just raw Yul programs but `yul-phaser` is prepared to handle them. +These files contain whole Yul objects rather than just raw Yul programs but `yul-phaser` is prepared to handle them too. + +#### Using optimisation step sequences with the compiler +You can tell Yul optimiser to use a specific sequence for your code by passing `--yul-optimizations` option to `solc`: + +``` bash +solc/solc --optimize --ir-optimized --yul-optimizations +``` ### How to choose good parameters Choosing good parameters for a genetic algorithm is not a trivial task but phaser's defaults are generally enough to find a sequence that gives results comparable or better than one hand-crafted by an experienced developer for a given set of programs.