diff --git a/.circleci/build_win.ps1 b/.circleci/build_win.ps1 new file mode 100644 index 000000000..66f9be33a --- /dev/null +++ b/.circleci/build_win.ps1 @@ -0,0 +1,18 @@ +$ErrorActionPreference = "Stop" + +cd "$PSScriptRoot\.." + +if ("$Env:FORCE_RELEASE") { + New-Item prerelease.txt -type file + Write-Host "Building release version." +} + +mkdir build +cd build +$boost_dir=(Resolve-Path $PSScriptRoot\..\deps\boost\lib\cmake\Boost-*) +..\deps\cmake\bin\cmake -G "Visual Studio 16 2019" -DBoost_DIR="$boost_dir\" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_INSTALL_PREFIX="$PSScriptRoot\..\upload" .. +if ( -not $? ) { throw "CMake configure failed." } +msbuild solidity.sln /p:Configuration=Release /m:5 /v:minimal +if ( -not $? ) { throw "Build failed." } +..\deps\cmake\bin\cmake --build . -j 5 --target install --config Release +if ( -not $? ) { throw "Install target failed." } diff --git a/.circleci/config.yml b/.circleci/config.yml index 91ba3a4e0..daefe4472 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,23 +9,26 @@ version: 2.1 parameters: ubuntu-1804-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu1804-2 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:9ab317e583c395e50884ba82e9f99811c374344cea4c550725be8ec836e07acc" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu1804-3 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:19f613d2ac47fedff654dacef984d8a64726c4d67ae8f2667a85ee7d97ac4c1c" ubuntu-2004-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-2 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:cbfa42d8ecbe94391ba8837e218869242666de7a0da6ccac065a856c85b6a6a0" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-3 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:aeedbe7390a7383815f0cf0f8a1b8bf84dc5e334a3b0043ebcdf8b1bdbe80a81" ubuntu-2004-clang-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-2 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:7a4d5271b5552139d9f2caefc50d42f401bf74132cf8f253e199e11c80ab42de" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-3 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:2593c15689dee5b5bdfff96a36c8c68a468cd3b147c41f75b820b8fabc257be9" ubuntu-1604-clang-ossfuzz-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-3 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:6fa6914bd81abcac4b162c738e6ff05d87cefe7655e3859c7a827e5a8ec20dc7" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-4 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:842126b164b3542f05bff2611459e21edc7e3e2c81ca9d1f43396c8cf066f7ca" emscripten-docker-image: type: string - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:d557d015918c3cf68b0d22839bab41013f0757b651a7fef21595f89721dbebcc" + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c" + +orbs: + win: circleci/windows@2.2.0 defaults: @@ -64,6 +67,10 @@ defaults: path: build/solc/solc destination: solc + # windows artifacts + - artifact_solc_windows: &artifact_solc_windows + path: upload/ + # compiled tool executable target - artifacts_tools: &artifacts_tools path: build/tools/solidity-upgrade @@ -107,14 +114,17 @@ defaults: - run_soltest: &run_soltest name: soltest + no_output_timeout: 30m command: ./.circleci/soltest.sh - run_soltest_all: &run_soltest_all name: soltest_all + no_output_timeout: 30m command: ./.circleci/soltest_all.sh - run_cmdline_tests: &run_cmdline_tests name: command line tests + no_output_timeout: 30m command: ./test/cmdlineTests.sh - run_docs_pragma_min_version: &run_docs_pragma_min_version @@ -163,7 +173,6 @@ defaults: at: build - run: <<: *run_soltest - no_output_timeout: 30m - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results @@ -175,7 +184,6 @@ defaults: at: build - run: <<: *run_soltest - no_output_timeout: 30m - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results @@ -207,6 +215,11 @@ defaults: requires: - b_ubu_release + - workflow_archlinux: &workflow_archlinux + <<: *workflow_trigger_on_tags + requires: + - b_archlinux + - workflow_ubuntu2004_codecov: &workflow_ubuntu2004_codecov <<: *workflow_trigger_on_tags requires: @@ -237,6 +250,16 @@ defaults: requires: - b_ubu_ossfuzz + - workflow_win: &workflow_win + <<: *workflow_trigger_on_tags + requires: + - b_win + + - workflow_win_release: &workflow_win_release + <<: *workflow_trigger_on_tags + requires: + - b_win_release + # -------------------------------------------------------------------------- # Notification Templates - gitter_notify_failure: &gitter_notify_failure @@ -656,6 +679,25 @@ jobs: t_ubu_soltest: &t_ubu_soltest <<: *test_ubuntu2004 + t_archlinux_soltest: &t_archlinux_soltest + docker: + - image: archlinux/base + environment: + EVM: constantinople + OPTIMIZE: 0 + TERM: xterm + steps: + - run: + name: Install runtime dependencies + command: | + pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake z3 cvc4 git openssh tar + - checkout + - attach_workspace: + at: build + - run: *run_soltest + - store_test_results: *store_test_results + - store_artifacts: *artifacts_test_results + t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul docker: - image: << pipeline.parameters.ubuntu-2004-docker-image >> @@ -709,7 +751,6 @@ jobs: at: build - run: <<: *run_cmdline_tests - no_output_timeout: 30m - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results @@ -745,6 +786,7 @@ jobs: apt-get install -qqy --no-install-recommends nodejs npm cvc4 - run: name: Test solcjs + no_output_timeout: 30m command: | node --version npm --version @@ -851,6 +893,56 @@ jobs: - run: *gitter_notify_failure - run: *gitter_notify_success + b_win: &b_win + executor: + name: win/default + shell: powershell.exe + steps: + - checkout + - restore_cache: + keys: + - dependencies-win-{{ checksum "scripts/install_deps.ps1" }} + - run: + name: "Installing dependencies" + command: if ( -not (Test-Path .\deps\boost) ) { .\scripts\install_deps.ps1 } + - save_cache: + key: dependencies-win-{{ checksum "scripts/install_deps.ps1" }} + paths: + - .\deps\boost + - .\deps\cmake + - run: + name: "Building solidity" + command: .circleci/build_win.ps1 + - run: + name: "Run solc.exe to make sure build was successful." + command: .\build\solc\Release\solc.exe --version + - store_artifacts: *artifact_solc_windows + - persist_to_workspace: *artifacts_build_dir + + b_win_release: + <<: *b_win + environment: + FORCE_RELEASE: ON + + t_win: &t_win + executor: + name: win/default + shell: powershell.exe + steps: + - checkout + - attach_workspace: + at: build + - run: + name: "Install evmone" + command: scripts/install_evmone.ps1 + - run: + name: "Run soltest" + command: .circleci/soltest.ps1 + - store_artifacts: *artifacts_test_results + + t_win_release: + <<: *t_win + workflows: version: 2 @@ -869,7 +961,6 @@ workflows: # build-only - b_docs: *workflow_trigger_on_tags - - b_archlinux: *workflow_trigger_on_tags - b_ubu_cxx20: *workflow_trigger_on_tags - b_ubu_ossfuzz: *workflow_trigger_on_tags @@ -878,6 +969,10 @@ workflows: - t_osx_cli: *workflow_osx - t_osx_soltest: *workflow_osx + # ArchLinux build and tests + - b_archlinux: *workflow_trigger_on_tags + - t_archlinux_soltest: *workflow_archlinux + # Ubuntu build and tests - b_ubu: *workflow_trigger_on_tags - b_ubu18: *workflow_trigger_on_tags @@ -899,6 +994,12 @@ workflows: - t_ems_compile_ext_gnosis: *workflow_emscripten - t_ems_compile_ext_zeppelin: *workflow_emscripten + # Windows build and tests + - b_win: *workflow_trigger_on_tags + - b_win_release: *workflow_trigger_on_tags + - t_win: *workflow_win + - t_win_release: *workflow_win_release + nightly: triggers: diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index 064680139..1cc16a9c9 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -43,13 +43,13 @@ then ./scripts/install_obsolete_jsoncpp_1_7_4.sh # z3 - wget https://github.com/Z3Prover/z3/releases/download/z3-4.8.8/z3-4.8.8-x64-osx-10.14.6.zip - unzip z3-4.8.8-x64-osx-10.14.6.zip - rm -f z3-4.8.8-x64-osx-10.14.6.zip - cp z3-4.8.8-x64-osx-10.14.6/bin/libz3.a /usr/local/lib - cp z3-4.8.8-x64-osx-10.14.6/bin/z3 /usr/local/bin - cp z3-4.8.8-x64-osx-10.14.6/include/* /usr/local/include - rm -rf z3-4.8.8-x64-osx-10.14.6 + wget https://github.com/Z3Prover/z3/releases/download/z3-4.8.9/z3-4.8.9-x64-osx-10.14.6.zip + unzip z3-4.8.9-x64-osx-10.14.6.zip + rm -f z3-4.8.9-x64-osx-10.14.6.zip + cp z3-4.8.9-x64-osx-10.14.6/bin/libz3.a /usr/local/lib + cp z3-4.8.9-x64-osx-10.14.6/bin/z3 /usr/local/bin + cp z3-4.8.9-x64-osx-10.14.6/include/* /usr/local/include + rm -rf z3-4.8.9-x64-osx-10.14.6 # evmone wget https://github.com/ethereum/evmone/releases/download/v0.4.0/evmone-0.4.0-darwin-x86_64.tar.gz diff --git a/.circleci/soltest.ps1 b/.circleci/soltest.ps1 new file mode 100755 index 000000000..6b67adb13 --- /dev/null +++ b/.circleci/soltest.ps1 @@ -0,0 +1,12 @@ +$ErrorActionPreference = "Stop" + +cd "$PSScriptRoot\.." + +.\build\solc\Release\solc.exe --version +if ( -not $? ) { throw "Cannot execute solc --version." } + +mkdir test_results +.\build\test\Release\soltest.exe --color_output=no --show_progress=yes --logger=JUNIT,error,test_results/result.xml -- --no-smt +if ( -not $? ) { throw "Unoptimized soltest run failed." } +.\build\test\Release\soltest.exe --color_output=no --show_progress=yes --logger=JUNIT,error,test_results/result_opt.xml -- --optimize --no-smt +if ( -not $? ) { throw "Optimized soltest run failed." } \ No newline at end of file diff --git a/.circleci/soltest_all.sh b/.circleci/soltest_all.sh index 7b1fb053b..78cc1137d 100755 --- a/.circleci/soltest_all.sh +++ b/.circleci/soltest_all.sh @@ -30,7 +30,7 @@ REPODIR="$(realpath $(dirname $0)/..)" EVM_VALUES=(homestead byzantium constantinople petersburg istanbul) OPTIMIZE_VALUES=(0 1) -STEPS=$(( 1 + ${#EVM_VALUES[@]} * ${#OPTIMIZE_VALUES[@]} )) +STEPS=$(( 2 + ${#EVM_VALUES[@]} * ${#OPTIMIZE_VALUES[@]} )) if (( $CIRCLE_NODE_TOTAL )) && (( $CIRCLE_NODE_TOTAL > 1 )) then @@ -57,7 +57,12 @@ echo "Running steps $RUN_STEPS..." STEP=1 -[[ " $RUN_STEPS " =~ " $STEP " ]] && EVM=istanbul OPTIMIZE=1 ABI_ENCODER_V2=1 "${REPODIR}/.circleci/soltest.sh" +# Run SMTChecker tests separately, as the heaviest expected run. +[[ " $RUN_STEPS " =~ " $STEP " ]] && EVM=istanbul OPTIMIZE=1 ABI_ENCODER_V2=1 BOOST_TEST_ARGS="-t smtCheckerTests/*" "${REPODIR}/.circleci/soltest.sh" +STEP=$(($STEP + 1)) + +# Run without SMTChecker tests. +[[ " $RUN_STEPS " =~ " $STEP " ]] && EVM=istanbul OPTIMIZE=1 ABI_ENCODER_V2=1 BOOST_TEST_ARGS="-t !smtCheckerTests" "${REPODIR}/.circleci/soltest.sh" STEP=$(($STEP + 1)) for OPTIMIZE in ${OPTIMIZE_VALUES[@]} diff --git a/.travis.yml b/.travis.yml index 3d00a974d..f9105e246 100644 --- a/.travis.yml +++ b/.travis.yml @@ -113,7 +113,7 @@ matrix: before_install: - nvm install 10 - nvm use 10 - - docker pull solbuildpackpusher/solidity-buildpack-deps@sha256:d557d015918c3cf68b0d22839bab41013f0757b651a7fef21595f89721dbebcc + - docker pull solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c env: - SOLC_EMSCRIPTEN=On - SOLC_INSTALL_DEPS_TRAVIS=Off diff --git a/CMakeLists.txt b/CMakeLists.txt index fba1830b9..b6797632b 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.7.1") +set(PROJECT_VERSION "0.7.2") # 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 8f27a4fdb..df123433e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,43 @@ +### 0.7.2 (2020-09-28) + +Important Bugfixes: + * Type Checker: Disallow two or more free functions with identical name (potentially imported and aliased) and parameter types. + + +Compiler Features: + * Export compiler-generated utility sources via standard-json or combined-json. + * Optimizer: Optimize ``exp`` when base is 0, 1 or 2. + * SMTChecker: Keep knowledge about string literals, even through assignment, and thus support the ``.length`` property properly. + * SMTChecker: Support ``address`` type conversion with literals, e.g. ``address(0)``. + * SMTChecker: Support ``revert()``. + * SMTChecker: Support ``type(T).min``, ``type(T).max``, and ``type(I).interfaceId``. + * SMTChecker: Support compound and, or, and xor operators. + * SMTChecker: Support events and low-level logs. + * SMTChecker: Support fixed bytes index access. + * SMTChecker: Support memory allocation, e.g. ``new bytes(123)``. + * SMTChecker: Support shifts. + * SMTChecker: Support structs. + * Type Checker: Explain why oversized hex string literals can not be explicitly converted to a shorter ``bytesNN`` type. + * Type Checker: More detailed error messages why implicit conversions fail. + * Type Checker: Report position of first invalid UTF-8 sequence in ``unicode""`` literals. + * Yul IR Generator: Report source locations related to unimplemented features. + * Yul Optimizer: Inline into functions further down in the call graph first. + * Yul Optimizer: Prune unused parameters in functions. + * Yul Optimizer: Try to simplify function names. + + +Bugfixes: + * Code generator: Fix internal error on stripping dynamic types from return parameters on EVM versions without ``RETURNDATACOPY``. + * Type Checker: Add missing check against nested dynamic arrays in ABI encoding functions when ABIEncoderV2 is disabled. + * Type Checker: Correct the error message for invalid named parameter in a call to refer to the right argument. + * Type Checker: Correct the warning for homonymous, but not shadowing declarations. + * Type Checker: Disallow ``virtual`` for modifiers in libraries. + * Type system: Fix internal error on implicit conversion of contract instance to the type of its ``super``. + * Type system: Fix internal error on implicit conversion of string literal to a calldata string. + * Type system: Fix named parameters in overloaded function and event calls being matched incorrectly if the order differs from the declaration. + * ViewPureChecker: Prevent visibility check on constructors. + + ### 0.7.1 (2020-09-02) Language Features: @@ -26,6 +66,7 @@ Bugfixes: * SMTChecker: Fix internal error on lvalue unary operators with tuples. * SMTChecker: Fix internal error on tuple assignment. * SMTChecker: Fix internal error on tuples of one element that have tuple type. + * SMTChecker: Fix internal error when using imported code. * SMTChecker: Fix soundness of array ``pop``. * Type Checker: Disallow ``using for`` directive inside interfaces. * Type Checker: Disallow signed literals as exponent in exponentiation operator. diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index 069098f20..e1426994b 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -25,11 +25,13 @@ - [ ] Create a pull request from ``develop`` to ``release``, wait for the tests, then merge it. - [ ] Make a final check that there are no platform-dependency issues in the ``solidity-test-bytecode`` repository. - [ ] Wait for the tests for the commit on ``release``, create a release in Github, creating the tag (click the `PUBLISH RELEASE` button on the release page.) - - [ ] Wait for the CI runs on the tag itself (travis and appveyor should push artifacts onto the Github release page). + - [ ] Wait for the CI runs on the tag itself (travis should push artifacts onto the Github release page). + - [ ] Take the ``solc.exe`` binary from the ``b_win_release`` run of the released commit in circle-ci and add it to the release page as ``solc-windows.exe``. - [ ] Run ``scripts/create_source_tarball.sh`` while being on the tag to create the source tarball. Make sure to create ``prerelease.txt`` before: (``echo -n > prerelease.txt``). This will create the tarball in a directory called ``upload``. - [ ] Take the tarball from the upload directory (its name should be ``solidity_x.x.x.tar.gz``, otherwise ``prerelease.txt`` was missing in the step before) and upload the source tarball to the release page. ### Homebrew and MacOS + - [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/Homebrew/homebrew-core/blob/master/Formula/solidity.rb - [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb - [ ] Take the binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``. diff --git a/appveyor.yml b/appveyor.yml index d7211e14b..15ad9b57b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -59,7 +59,7 @@ install: before_build: - if not exist build mkdir build - cd build - - cmake -G "Visual Studio 15 2017 Win64" .. -DTESTS=On + - cmake -G "Visual Studio 15 2017 Win64" .. -DTESTS=On -DBoost_USE_STATIC_RUNTIME=OFF build_script: - msbuild solidity.sln /p:Configuration=%CONFIGURATION% /m:%NUMBER_OF_PROCESSORS% /v:minimal - cd %APPVEYOR_BUILD_FOLDER% diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index d8bca8a31..04cb876be 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -25,6 +25,9 @@ set(ETH_SCRIPTS_DIR ${ETH_CMAKE_DIR}/scripts) ## use multithreaded boost libraries, with -mt suffix set(Boost_USE_MULTITHREADED ON) option(Boost_USE_STATIC_LIBS "Link Boost statically" ON) +if(WIN32) + option(Boost_USE_STATIC_RUNTIME "Link Boost against static C++ runtime libraries" ON) +endif() set(BOOST_COMPONENTS "filesystem;unit_test_framework;program_options;system") diff --git a/cmake/EthPolicy.cmake b/cmake/EthPolicy.cmake index 4e29898cb..cc404e794 100644 --- a/cmake/EthPolicy.cmake +++ b/cmake/EthPolicy.cmake @@ -15,5 +15,9 @@ macro (eth_policy) # do not interpret if() arguments as variables! cmake_policy(SET CMP0054 NEW) endif() -endmacro() + if (POLICY CMP0091) + # Allow selecting MSVC runtime library using CMAKE_MSVC_RUNTIME_LIBRARY. + cmake_policy(SET CMP0091 NEW) + endif() +endmacro() diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index 80a16f8d5..29b8f5f05 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -34,6 +34,12 @@ if(CMAKE_VERSION VERSION_GREATER 3.1) set(byproducts BUILD_BYPRODUCTS "${JSONCPP_LIBRARY}") endif() +# Propagate CMAKE_MSVC_RUNTIME_LIBRARY on Windows builds, if set. +if (WIN32 AND POLICY CMP0091 AND CMAKE_MSVC_RUNTIME_LIBRARY) + list(APPEND JSONCPP_CMAKE_ARGS "-DCMAKE_POLICY_DEFAULT_CMP0091:STRING=NEW") + list(APPEND JSONCPP_CMAKE_ARGS "-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}") +endif() + ExternalProject_Add(jsoncpp-project PREFIX "${prefix}" DOWNLOAD_DIR "${CMAKE_SOURCE_DIR}/deps/downloads" @@ -51,6 +57,7 @@ ExternalProject_Add(jsoncpp-project -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF -DCMAKE_CXX_FLAGS=${JSONCPP_CXX_FLAGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + ${JSONCPP_CMAKE_ARGS} ${byproducts} ) diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index e46d0d650..ddffaf3f4 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -537,7 +537,7 @@ For example, :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Test { diff --git a/docs/assembly.rst b/docs/assembly.rst index b54800d46..778f90fe5 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -140,7 +140,7 @@ Local Solidity variables are available for assignments, for example: .. code:: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract C { uint b; diff --git a/docs/brand-guide.rst b/docs/brand-guide.rst index dda438533..fc03f35d9 100644 --- a/docs/brand-guide.rst +++ b/docs/brand-guide.rst @@ -70,6 +70,8 @@ Solidity Logo Guidelines .. image:: logo.svg :width: 256 +*(Right click on the logo to download it.)* + Please do not: - Change the ratio of the logo (do not stretch it or cut it). diff --git a/docs/bugs.json b/docs/bugs.json index 34325f45b..ec1d75670 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "FreeFunctionRedefinition", + "summary": "The compiler does not flag an error when two or more free functions with the same name and parameter types are defined in a source unit or when an imported free function alias shadows another free function with a different name but identical parameter types.", + "description": "In contrast to functions defined inside contracts, free functions with identical names and parameter types did not create an error. Both definition of free functions with identical name and parameter types and an imported free function with an alias that shadows another function with a different name but identical parameter types were permitted due to which a call to either the multiply defined free function or the imported free function alias within a contract led to the execution of that free function which was defined first within the source unit. Subsequently defined identical free function definitions were silently ignored and their code generation was skipped.", + "introduced": "0.7.1", + "fixed": "0.7.2", + "severity": "low" + }, { "name": "UsingForCalldata", "summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 4acdc7701..8ebe8b060 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1187,7 +1187,13 @@ "released": "2020-07-28" }, "0.7.1": { - "bugs": [], + "bugs": [ + "FreeFunctionRedefinition" + ], "released": "2020-09-02" + }, + "0.7.2": { + "bugs": [], + "released": "2020-09-28" } } \ No newline at end of file diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 5dcc33ed6..3c9d3d52a 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -28,7 +28,7 @@ you receive the funds of the person who is now the richest. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract WithdrawalContract { address public richest; @@ -62,7 +62,7 @@ This is as opposed to the more intuitive sending pattern: :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract SendContract { address payable public richest; diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 06bc4189e..23da14a3c 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -26,7 +26,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.99 <0.8.0; + pragma solidity ^0.7.0; contract C { uint constant X = 32**22 + 8; diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index e7c97c33d..cb6b30df5 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -277,7 +277,7 @@ neither a receive Ether nor a payable fallback function is present, the contract cannot receive Ether through regular transactions and throws an exception. -In the worst case, the fallback function can only rely on 2300 gas being +In the worst case, the ``receive`` function can only rely on 2300 gas being available (for example when ``send`` or ``transfer`` is used), leaving little room to perform other operations except basic logging. The following operations will consume more gas than the 2300 gas stipend: diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index 533f74da4..5c9b904b7 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -39,7 +39,7 @@ Details are given in the following example. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Owned { @@ -127,7 +127,7 @@ 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.99 <0.8.0; + pragma solidity ^0.7.0; contract owned { constructor() { owner = msg.sender; } @@ -157,7 +157,7 @@ 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.99 <0.8.0; + pragma solidity ^0.7.0; contract owned { constructor() { owner = msg.sender; } @@ -214,7 +214,7 @@ The following example demonstrates changing mutability and visibility: :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Base { @@ -405,7 +405,7 @@ equivalent to ``constructor() {}``. For example: :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; abstract contract A { uint public a; @@ -442,7 +442,7 @@ 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.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Base { uint x; @@ -523,7 +523,7 @@ One area where inheritance linearization is especially important and perhaps not :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Base1 { constructor() {} diff --git a/docs/contributing.rst b/docs/contributing.rst index a5932c8fe..eec3524e9 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -2,22 +2,25 @@ Contributing ############ -Help is always appreciated! +Help is always welcome and there are plenty of options how you can contribute to Solidity. -To get started, you can try :ref:`building-from-source` in order to familiarize -yourself with the components of Solidity and the build process. Also, it may be -useful to become well-versed at writing smart-contracts in Solidity. +In particular, we appreciate support in the following areas: -In particular, we need help in the following areas: - -* Improving the documentation -* Responding to questions from other users on `StackExchange - `_ and the `Solidity Gitter - `_ +* Reporting issues. * Fixing and responding to `Solidity's GitHub issues `_, especially those tagged as `good first issue `_ which are meant as introductory issues for external contributors. +* Improving the documentation. +* Translating the documentation into more languages. +* Responding to questions from other users on `StackExchange + `_ and the `Solidity Gitter Chat + `_. +* Getting involved in the language design process by joining language design calls, proposing language changes or new features and providing feedback. + +To get started, you can try :ref:`building-from-source` in order to familiarize +yourself with the components of Solidity and the build process. Also, it may be +useful to become well-versed at writing smart-contracts in Solidity. Please note that this project is released with a `Contributor Code of Conduct `_. By participating in this project - in the issues, pull requests, or Gitter channels - you agree to abide by its terms. @@ -27,8 +30,8 @@ Team Calls If you have issues or pull requests to discuss, or are interested in hearing what the team and contributors are working on, you can join our public team calls: -- Mondays at 12pm CET/CEST -- Wednesdays at 2pm CET/CEST +- Mondays at 12pm CET/CEST. +- Wednesdays at 2pm CET/CEST. Both calls take place on `Google Meet `_. @@ -39,12 +42,12 @@ To report an issue, please use the `GitHub issues tracker `_. When reporting issues, please mention the following details: -* Which version of Solidity you are using -* What was the source code (if applicable) -* Which platform are you running on -* How to reproduce the issue -* What was the result of the issue -* What the expected behaviour is +* Which version of Solidity you are using. +* What was the source code (if applicable). +* Which platform are you running on. +* How to reproduce the issue. +* What was the result of the issue. +* What the expected behaviour is. Reducing the source code that caused the issue to a bare minimum is always very helpful and sometimes even clarifies a misunderstanding. @@ -66,7 +69,7 @@ test cases under ``test/`` (see below). However, if you are making a larger change, please consult with the `Solidity Development Gitter channel `_ (different from the one mentioned above, this one is -focused on compiler and language development instead of language use) first. +focused on compiler and language development instead of language usage) first. New features and bugfixes should be added to the ``Changelog.md`` file: please follow the style of previous entries, when applicable. @@ -78,7 +81,7 @@ ensure that it builds locally before submitting a pull request. Thank you for your help! -Running the compiler tests +Running the Compiler Tests ========================== Prerequisites @@ -91,7 +94,7 @@ in the current directory, installed on the system level, or the ``deps`` folder in the project top level. The required file is called ``libevmone.so`` on Linux systems, ``evmone.dll`` on Windows systems and ``libevmone.dylib`` on macOS. -Running the tests +Running the Tests ----------------- Solidity includes different types of tests, most of them bundled into the @@ -155,7 +158,7 @@ you have access to functions and variables in which you can break or print with. The CI runs additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target. -Writing and running syntax tests +Writing and Running Syntax Tests -------------------------------- Syntax tests check that the compiler generates the correct error messages for invalid code @@ -366,7 +369,7 @@ the string parameter ``name`` is non-empty. Documentation Style Guide ========================= -The following are style recommendations specifically for documentation +In the following section you find style recommendations specifically focusing on documentation contributions to Solidity. English Language @@ -394,10 +397,10 @@ title. For example, the following are all correct: -* Title Case for Headings -* For Headings Use Title Case -* Local and State Variable Names -* Order of Layout +* Title Case for Headings. +* For Headings Use Title Case. +* Local and State Variable Names. +* Order of Layout. Expand Contractions ------------------- @@ -450,3 +453,21 @@ Running Documentation Tests Make sure your contributions pass our documentation tests by running ``./scripts/docs.sh`` that installs dependencies needed for documentation and checks for any problems such as broken links or syntax issues. + +Solidity Language Design +======================== + +If you want to get involved in the language design process and share your ideas, please join the `solidity-users forum `_, +where existing properties of the language and proposals for new features can be discussed. + +We regularly host language design discussion calls, in which selected topics, issues or feature implementations are debated in detail. The invitation +to those calls is shared via the aforementioned forum. We are also sharing feedback surveys and other language design relevant content in this forum. + +For ad-hoc cases and questions you can reach out to us via the `Solidity-dev Gitter channel `_, a +dedicated chatroom for conversations around the Solidity compiler and language development. + +You can follow the implementation status of new features in the `Solidity Github project `_. +Issues in the design backlog need further specification and will either be discussed in a language design call or in a regular team call. You can +see the upcoming changes for the next breaking release by changing from the default branch (`develop`) to the `breaking branch `_. + +We are happy to hear your thoughts on how we can improve the language design process to be even more collaborative and transparent. \ No newline at end of file diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 3b4bc4448..ff2f6ad6b 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -19,7 +19,7 @@ Solidity also supports exception handling in the form of ``try``/``catch``-state but only for :ref:`external function calls ` and contract creation calls. -Parentheses can *not* be omitted for conditionals, but curly brances can be omitted +Parentheses can *not* be omitted for conditionals, but curly braces can be omitted around single-statement bodies. Note that there is no type conversion from non-boolean to boolean types as @@ -105,8 +105,12 @@ otherwise, the ``value`` option would not be available. parentheses at the end perform the actual call. So in this case, the function is not called and the ``value`` and ``gas`` settings are lost. -Function calls cause exceptions if the called contract does not exist (in the -sense that the account does not contain code) or if the called contract itself +Due to the fact that the EVM considers a call to a non-existing contract to +always succeed, Solidity uses the ``extcodesize`` opcode to check that +the contract that is about to be called actually exists (it contains code) +and causes an exception if it does not. + +Function calls also cause exceptions if the called contract itself throws an exception or goes out of gas. .. warning:: @@ -188,7 +192,7 @@ is compiled so recursive creation-dependencies are not possible. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract D { uint public x; @@ -244,7 +248,7 @@ which only need to be created if there is a dispute. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract D { uint public x; diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index 3034b6915..1843d32b1 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -25,7 +25,7 @@ to receive their money - contracts cannot activate themselves. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract SimpleAuction { // Parameters of the auction. Times are either @@ -186,7 +186,7 @@ invalid bids. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract BlindAuction { struct Bid { diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index 2ff293f48..0724b1766 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -61,12 +61,11 @@ For a contract that fulfils payments, the signed message must include: 2. The amount to be transferred. 3. Protection against replay attacks. -A replay attack is when a signed message is reused to claim authorization for -a second action. -To avoid replay attacks we use the same as in Ethereum transactions -themselves, a so-called nonce, which is the number of transactions sent by an -account. -The smart contract checks if a nonce is used multiple times. +A replay attack is when a signed message is reused to claim +authorization for a second action. To avoid replay attacks +we use the same technique as in Ethereum transactions themselves, +a so-called nonce, which is the number of transactions sent by +an account. The smart contract checks if a nonce is used multiple times. Another type of replay attack can occur when the owner deploys a ``ReceiverPays`` smart contract, makes some @@ -143,7 +142,7 @@ The full contract :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract ReceiverPays { address owner = msg.sender; @@ -340,7 +339,7 @@ The full contract :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract SimplePaymentChannel { address payable public sender; // The account sending payments. diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst index bae6a3a50..bd755c0b4 100644 --- a/docs/examples/safe-remote.rst +++ b/docs/examples/safe-remote.rst @@ -26,7 +26,7 @@ you can use state machine-like constructs inside a contract. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Purchase { uint public value; @@ -143,4 +143,4 @@ you can use state machine-like constructs inside a contract. seller.transfer(3 * value); } - } \ No newline at end of file + } diff --git a/docs/examples/voting.rst b/docs/examples/voting.rst index 56a880edf..9991f298d 100644 --- a/docs/examples/voting.rst +++ b/docs/examples/voting.rst @@ -33,7 +33,7 @@ of votes. :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; /// @title Voting with delegation. contract Ballot { diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 7a5c52d71..62ea63c6d 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -163,8 +163,13 @@ Homebrew formula directly from Github. View `solidity.rb commits on Github `_. -Follow the history links until you have a raw file link of a -specific commit of ``solidity.rb``. +Copy the commit hash of the version you want and check it out on your machine. + +.. code-block:: bash + + git clone https://github.com/ethereum/homebrew-ethereum.git + cd homebrew-ethereum + git checkout Install it using ``brew``: @@ -172,7 +177,7 @@ Install it using ``brew``: brew unlink solidity # eg. Install 0.4.8 - brew install https://raw.githubusercontent.com/ethereum/homebrew-ethereum/77cce03da9f289e5a3ffe579840d3c5dc0a62717/solidity.rb + brew install solidity.rb Gentoo Linux has an `Ethereum overlay `_ that contains a solidity package. After the overlay is setup, ``solc`` can be installed in x86_64 architectures by: @@ -225,7 +230,7 @@ The following C++ compilers and their minimum versions can build the Solidity co - `GCC `_, version 5+ - `Clang `_, version 3.4+ -- `MSVC `_, version 2017+ +- `MSVC `_, version 2019+ Prerequisites - macOS --------------------- @@ -257,29 +262,29 @@ You need to install the following dependencies for Windows builds of Solidity: +-----------------------------------+-------------------------------------------------------+ | Software | Notes | +===================================+=======================================================+ -| `Visual Studio 2017 Build Tools`_ | C++ compiler | +| `Visual Studio 2019 Build Tools`_ | C++ compiler | +-----------------------------------+-------------------------------------------------------+ -| `Visual Studio 2017`_ (Optional) | C++ compiler and dev environment. | +| `Visual Studio 2019`_ (Optional) | C++ compiler and dev environment. | +-----------------------------------+-------------------------------------------------------+ If you already have one IDE and only need the compiler and libraries, -you could install Visual Studio 2017 Build Tools. +you could install Visual Studio 2019 Build Tools. -Visual Studio 2017 provides both IDE and necessary compiler and libraries. -So if you have not got an IDE and prefer to develop solidity, Visual Studio 2017 +Visual Studio 2019 provides both IDE and necessary compiler and libraries. +So if you have not got an IDE and prefer to develop solidity, Visual Studio 2019 may be a choice for you to get everything setup easily. Here is the list of components that should be installed -in Visual Studio 2017 Build Tools or Visual Studio 2017: +in Visual Studio 2019 Build Tools or Visual Studio 2019: * Visual Studio C++ core features -* VC++ 2017 v141 toolset (x86,x64) +* VC++ 2019 v141 toolset (x86,x64) * Windows Universal CRT SDK * Windows 8.1 SDK * C++/CLI support -.. _Visual Studio 2017: https://www.visualstudio.com/vs/ -.. _Visual Studio 2017 Build Tools: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017 +.. _Visual Studio 2019: https://www.visualstudio.com/vs/ +.. _Visual Studio 2019 Build Tools: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019 Dependencies Helper Script -------------------------- @@ -295,7 +300,10 @@ Or, on Windows: .. code-block:: bat - scripts\install_deps.bat + scripts\install_deps.ps1 + +Note that the latter command will install ``boost`` and ``cmake`` to the ``deps`` subdirectory, while the former command +will attempt to install the dependencies globally. Clone the Repository -------------------- @@ -357,11 +365,14 @@ And for Windows: mkdir build cd build - cmake -G "Visual Studio 15 2017 Win64" .. + cmake -G "Visual Studio 16 2019 Win64" .. -This latter set of instructions should result in the creation of -**solidity.sln** in that build directory. Double-clicking on that file -should result in Visual Studio firing up. We suggest building +In case you want to use the version of boost installed by ``./scripts/install_deps.ps1``, you will +additionally need to pass ``-DBoost_DIR="..\deps\boost\lib\cmake\Boost-*"`` and ``-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded`` +as arguments to the call to ``cmake``. + +This should result in the creation of **solidity.sln** in that build directory. +Double-clicking on that file should result in Visual Studio firing up. We suggest building **Release** configuration, but all others work. Alternatively, you can build for Windows on the command-line, like so: diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 3a6d5dfd6..d8e04a81f 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -201,7 +201,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.6.99 <0.8.0; + pragma solidity ^0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE contract TxUserWallet { @@ -222,7 +222,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.99 <0.8.0; + pragma solidity ^0.7.0; interface TxUserWallet { function transferTo(address payable dest, uint amount) external; diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 73a65df08..92137b223 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -300,7 +300,7 @@ Within a grouping, place the ``view`` and ``pure`` functions last. Yes:: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract A { constructor() { @@ -337,7 +337,7 @@ Yes:: No:: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract A { @@ -758,7 +758,7 @@ manner as modifiers if the function declaration is long or hard to read. Yes:: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; // Base contracts just to make this compile contract B { @@ -790,7 +790,7 @@ Yes:: No:: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; // Base contracts just to make this compile @@ -1012,7 +1012,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.6.99 <0.8.0; + pragma solidity ^0.7.0; // Owned.sol @@ -1048,7 +1048,7 @@ and in ``Congress.sol``:: No:: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; // owned.sol diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 336cf5b2e..6eb4c01bf 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -434,7 +434,7 @@ Array slices are useful to ABI-decode secondary data passed in function paramete :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; contract Proxy { /// @dev Address of the client contract managed by proxy i.e., this contract diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 008855179..0f6d41b4f 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -314,6 +314,7 @@ Input Description // evm.bytecode.opcodes - Opcodes list // evm.bytecode.sourceMap - Source mapping (useful for debugging) // evm.bytecode.linkReferences - Link references (if unlinked object) + // evm.bytecode.generatedSources - Sources generated by the compiler // evm.deployedBytecode* - Deployed bytecode (has all the options that evm.bytecode has) // evm.deployedBytecode.immutableReferences - Map from AST ids to bytecode ranges that reference immutables // evm.methodIdentifiers - The list of function hashes @@ -427,6 +428,18 @@ Output Description "opcodes": "", // The source mapping as a string. See the source mapping definition. "sourceMap": "", + // Array of sources generated by the compiler. Currently only + // contains a single Yul file. + "generatedSources": [{ + // Yul AST + "ast": { ... } + // Source file in its text form (may contain comments) + "contents":"{ function abi_decode(start, end) -> data { data := calldataload(start) } }", + // Source file ID, used for source references, same "namespace" as the Solidity source files + "id": 2, + "language": "Yul", + "name": "#utility.yul" + }] // If given, this is an unlinked object. "linkReferences": { "libraryFile.sol": { @@ -693,7 +706,7 @@ have to be updated manually.) .. code-block:: Solidity - pragma solidity >0.6.99 <0.8.0; + pragma solidity ^0.7.0; // SPDX-License-Identifier: GPL-3.0 abstract contract C { // FIXME: remove constructor visibility and make the contract abstract diff --git a/docs/yul.rst b/docs/yul.rst index 7d064059b..619e23bab 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -243,7 +243,7 @@ Since variables are stored on the stack, they do not directly influence memory or storage, but they can be used as pointers to memory or storage locations in the built-in functions ``mstore``, ``mload``, ``sstore`` and ``sload``. -Future dialects migh introduce specific types for such pointers. +Future dialects might introduce specific types for such pointers. When a variable is referenced, its current value is copied. For the EVM, this translates to a ``DUP`` instruction. @@ -952,6 +952,26 @@ option. See :ref:`Using the Commandline Compiler ` for details about the Solidity linker. +memoryguard +^^^^^^^^^^^ + +This function is available in the EVM dialect with objects. The caller of +``let ptr := memoryguard(size)`` (where ``size`` has to be a literal number) +promises that they only use memory in either the range ``[0, size)`` or the +unbounded range starting at ``ptr``. + +Since the presence of a ``memoryguard`` call indicates that all memory access +adheres to this restriction, it allows the optimizer to perform additional +optimization steps, for example the stack limit evader, which attempts to move +stack variables that would otherwise be unreachable to memory. + +The Yul optimizer promises to only use the memory range ``[size, ptr)`` for its purposes. +If the optimizer does not need to reserve any memory, it holds that ``ptr == size``. + +``memoryguard`` can be called multiple times, but needs to have the same literal as argument +within one Yul subobject. If at least one ``memoryguard`` call is found in a subobject, +the additional optimiser steps will be run on it. + .. _yul-object: @@ -1110,6 +1130,7 @@ Abbreviation Full name ``L`` ``LoadResolver`` ``M`` ``LoopInvariantCodeMotion`` ``r`` ``RedundantAssignEliminator`` +``R`` ``ReasoningBasedSimplifier`` - highly experimental ``m`` ``Rematerialiser`` ``V`` ``SSAReverser`` ``a`` ``SSATransform`` @@ -1121,6 +1142,10 @@ Abbreviation Full name 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. +The ReasoningBasedSimplifier is an optimizer step that is currently not enabled +in the default set of steps. It uses an SMT solver to simplify arithmetic expressions +and boolean conditions. It has not received thorough testing or validation yet and can produce +non-reproducible results, so please use with care! .. _erc20yul: diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index c2cf1eef3..883de4c9f 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -71,51 +71,51 @@ std::vector> simplificationRuleListPart1( { using Word = typename Pattern::Word; using Builtins = typename Pattern::Builtins; - return std::vector> { + return std::vector>{ // arithmetic on constants - {Builtins::ADD(A, B), [=]{ return A.d() + B.d(); }, false}, - {Builtins::MUL(A, B), [=]{ return A.d() * B.d(); }, false}, - {Builtins::SUB(A, B), [=]{ return A.d() - B.d(); }, false}, - {Builtins::DIV(A, B), [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }, false}, - {Builtins::SDIV(A, B), [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }, false}, - {Builtins::MOD(A, B), [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }, false}, - {Builtins::SMOD(A, B), [=]{ return B.d() == 0 ? 0 : s2u(modWorkaround(u2s(A.d()), u2s(B.d()))); }, false}, - {Builtins::EXP(A, B), [=]{ return Word(boost::multiprecision::powm(bigint(A.d()), bigint(B.d()), bigint(1) << Pattern::WordSize)); }, false}, - {Builtins::NOT(A), [=]{ return ~A.d(); }, false}, - {Builtins::LT(A, B), [=]() -> Word { return A.d() < B.d() ? 1 : 0; }, false}, - {Builtins::GT(A, B), [=]() -> Word { return A.d() > B.d() ? 1 : 0; }, false}, - {Builtins::SLT(A, B), [=]() -> Word { return u2s(A.d()) < u2s(B.d()) ? 1 : 0; }, false}, - {Builtins::SGT(A, B), [=]() -> Word { return u2s(A.d()) > u2s(B.d()) ? 1 : 0; }, false}, - {Builtins::EQ(A, B), [=]() -> Word { return A.d() == B.d() ? 1 : 0; }, false}, - {Builtins::ISZERO(A), [=]() -> Word { return A.d() == 0 ? 1 : 0; }, false}, - {Builtins::AND(A, B), [=]{ return A.d() & B.d(); }, false}, - {Builtins::OR(A, B), [=]{ return A.d() | B.d(); }, false}, - {Builtins::XOR(A, B), [=]{ return A.d() ^ B.d(); }, false}, + {Builtins::ADD(A, B), [=]{ return A.d() + B.d(); }}, + {Builtins::MUL(A, B), [=]{ return A.d() * B.d(); }}, + {Builtins::SUB(A, B), [=]{ return A.d() - B.d(); }}, + {Builtins::DIV(A, B), [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }}, + {Builtins::SDIV(A, B), [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }}, + {Builtins::MOD(A, B), [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }}, + {Builtins::SMOD(A, B), [=]{ return B.d() == 0 ? 0 : s2u(modWorkaround(u2s(A.d()), u2s(B.d()))); }}, + {Builtins::EXP(A, B), [=]{ return Word(boost::multiprecision::powm(bigint(A.d()), bigint(B.d()), bigint(1) << Pattern::WordSize)); }}, + {Builtins::NOT(A), [=]{ return ~A.d(); }}, + {Builtins::LT(A, B), [=]() -> Word { return A.d() < B.d() ? 1 : 0; }}, + {Builtins::GT(A, B), [=]() -> Word { return A.d() > B.d() ? 1 : 0; }}, + {Builtins::SLT(A, B), [=]() -> Word { return u2s(A.d()) < u2s(B.d()) ? 1 : 0; }}, + {Builtins::SGT(A, B), [=]() -> Word { return u2s(A.d()) > u2s(B.d()) ? 1 : 0; }}, + {Builtins::EQ(A, B), [=]() -> Word { return A.d() == B.d() ? 1 : 0; }}, + {Builtins::ISZERO(A), [=]() -> Word { return A.d() == 0 ? 1 : 0; }}, + {Builtins::AND(A, B), [=]{ return A.d() & B.d(); }}, + {Builtins::OR(A, B), [=]{ return A.d() | B.d(); }}, + {Builtins::XOR(A, B), [=]{ return A.d() ^ B.d(); }}, {Builtins::BYTE(A, B), [=]{ return A.d() >= Pattern::WordSize / 8 ? 0 : (B.d() >> unsigned(8 * (Pattern::WordSize / 8 - 1 - A.d()))) & 0xff; - }, false}, - {Builtins::ADDMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) + bigint(B.d())) % C.d()); }, false}, - {Builtins::MULMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) * bigint(B.d())) % C.d()); }, false}, + }}, + {Builtins::ADDMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) + bigint(B.d())) % C.d()); }}, + {Builtins::MULMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) * bigint(B.d())) % C.d()); }}, {Builtins::SIGNEXTEND(A, B), [=]() -> Word { if (A.d() >= Pattern::WordSize / 8 - 1) return B.d(); unsigned testBit = unsigned(A.d()) * 8 + 7; Word mask = (Word(1) << testBit) - 1; return boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask; - }, false}, + }}, {Builtins::SHL(A, B), [=]{ if (A.d() >= Pattern::WordSize) return Word(0); return shlWorkaround(B.d(), unsigned(A.d())); - }, false}, + }}, {Builtins::SHR(A, B), [=]{ if (A.d() >= Pattern::WordSize) return Word(0); return B.d() >> unsigned(A.d()); - }, false} + }} }; } @@ -133,48 +133,48 @@ std::vector> simplificationRuleListPart2( using Builtins = typename Pattern::Builtins; return std::vector> { // invariants involving known constants - {Builtins::ADD(X, 0), [=]{ return X; }, false}, - {Builtins::ADD(0, X), [=]{ return X; }, false}, - {Builtins::SUB(X, 0), [=]{ return X; }, false}, - {Builtins::SUB(~Word(0), X), [=]() -> Pattern { return Builtins::NOT(X); }, false}, - {Builtins::MUL(X, 0), [=]{ return Word(0); }, true}, - {Builtins::MUL(0, X), [=]{ return Word(0); }, true}, - {Builtins::MUL(X, 1), [=]{ return X; }, false}, - {Builtins::MUL(1, X), [=]{ return X; }, false}, - {Builtins::MUL(X, Word(-1)), [=]() -> Pattern { return Builtins::SUB(0, X); }, false}, - {Builtins::MUL(Word(-1), X), [=]() -> Pattern { return Builtins::SUB(0, X); }, false}, - {Builtins::DIV(X, 0), [=]{ return Word(0); }, true}, - {Builtins::DIV(0, X), [=]{ return Word(0); }, true}, - {Builtins::DIV(X, 1), [=]{ return X; }, false}, - {Builtins::SDIV(X, 0), [=]{ return Word(0); }, true}, - {Builtins::SDIV(0, X), [=]{ return Word(0); }, true}, - {Builtins::SDIV(X, 1), [=]{ return X; }, false}, - {Builtins::AND(X, ~Word(0)), [=]{ return X; }, false}, - {Builtins::AND(~Word(0), X), [=]{ return X; }, false}, - {Builtins::AND(X, 0), [=]{ return Word(0); }, true}, - {Builtins::AND(0, X), [=]{ return Word(0); }, true}, - {Builtins::OR(X, 0), [=]{ return X; }, false}, - {Builtins::OR(0, X), [=]{ return X; }, false}, - {Builtins::OR(X, ~Word(0)), [=]{ return ~Word(0); }, true}, - {Builtins::OR(~Word(0), X), [=]{ return ~Word(0); }, true}, - {Builtins::XOR(X, 0), [=]{ return X; }, false}, - {Builtins::XOR(0, X), [=]{ return X; }, false}, - {Builtins::MOD(X, 0), [=]{ return Word(0); }, true}, - {Builtins::MOD(0, X), [=]{ return Word(0); }, true}, - {Builtins::EQ(X, 0), [=]() -> Pattern { return Builtins::ISZERO(X); }, false }, - {Builtins::EQ(0, X), [=]() -> Pattern { return Builtins::ISZERO(X); }, false }, - {Builtins::SHL(0, X), [=]{ return X; }, false}, - {Builtins::SHR(0, X), [=]{ return X; }, false}, - {Builtins::SHL(X, 0), [=]{ return Word(0); }, true}, - {Builtins::SHR(X, 0), [=]{ return Word(0); }, true}, - {Builtins::GT(X, 0), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }, false}, - {Builtins::LT(0, X), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }, false}, - {Builtins::GT(X, ~Word(0)), [=]{ return Word(0); }, true}, - {Builtins::LT(~Word(0), X), [=]{ return Word(0); }, true}, - {Builtins::GT(0, X), [=]{ return Word(0); }, true}, - {Builtins::LT(X, 0), [=]{ return Word(0); }, true}, - {Builtins::AND(Builtins::BYTE(X, Y), Word(0xff)), [=]() -> Pattern { return Builtins::BYTE(X, Y); }, false}, - {Builtins::BYTE(Word(Pattern::WordSize / 8 - 1), X), [=]() -> Pattern { return Builtins::AND(X, Word(0xff)); }, false} + {Builtins::ADD(X, 0), [=]{ return X; }}, + {Builtins::ADD(0, X), [=]{ return X; }}, + {Builtins::SUB(X, 0), [=]{ return X; }}, + {Builtins::SUB(~Word(0), X), [=]() -> Pattern { return Builtins::NOT(X); }}, + {Builtins::MUL(X, 0), [=]{ return Word(0); }}, + {Builtins::MUL(0, X), [=]{ return Word(0); }}, + {Builtins::MUL(X, 1), [=]{ return X; }}, + {Builtins::MUL(1, X), [=]{ return X; }}, + {Builtins::MUL(X, Word(-1)), [=]() -> Pattern { return Builtins::SUB(0, X); }}, + {Builtins::MUL(Word(-1), X), [=]() -> Pattern { return Builtins::SUB(0, X); }}, + {Builtins::DIV(X, 0), [=]{ return Word(0); }}, + {Builtins::DIV(0, X), [=]{ return Word(0); }}, + {Builtins::DIV(X, 1), [=]{ return X; }}, + {Builtins::SDIV(X, 0), [=]{ return Word(0); }}, + {Builtins::SDIV(0, X), [=]{ return Word(0); }}, + {Builtins::SDIV(X, 1), [=]{ return X; }}, + {Builtins::AND(X, ~Word(0)), [=]{ return X; }}, + {Builtins::AND(~Word(0), X), [=]{ return X; }}, + {Builtins::AND(X, 0), [=]{ return Word(0); }}, + {Builtins::AND(0, X), [=]{ return Word(0); }}, + {Builtins::OR(X, 0), [=]{ return X; }}, + {Builtins::OR(0, X), [=]{ return X; }}, + {Builtins::OR(X, ~Word(0)), [=]{ return ~Word(0); }}, + {Builtins::OR(~Word(0), X), [=]{ return ~Word(0); }}, + {Builtins::XOR(X, 0), [=]{ return X; }}, + {Builtins::XOR(0, X), [=]{ return X; }}, + {Builtins::MOD(X, 0), [=]{ return Word(0); }}, + {Builtins::MOD(0, X), [=]{ return Word(0); }}, + {Builtins::EQ(X, 0), [=]() -> Pattern { return Builtins::ISZERO(X); },}, + {Builtins::EQ(0, X), [=]() -> Pattern { return Builtins::ISZERO(X); },}, + {Builtins::SHL(0, X), [=]{ return X; }}, + {Builtins::SHR(0, X), [=]{ return X; }}, + {Builtins::SHL(X, 0), [=]{ return Word(0); }}, + {Builtins::SHR(X, 0), [=]{ return Word(0); }}, + {Builtins::GT(X, 0), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }}, + {Builtins::LT(0, X), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }}, + {Builtins::GT(X, ~Word(0)), [=]{ return Word(0); }}, + {Builtins::LT(~Word(0), X), [=]{ return Word(0); }}, + {Builtins::GT(0, X), [=]{ return Word(0); }}, + {Builtins::LT(X, 0), [=]{ return Word(0); }}, + {Builtins::AND(Builtins::BYTE(X, Y), Word(0xff)), [=]() -> Pattern { return Builtins::BYTE(X, Y); }}, + {Builtins::BYTE(Word(Pattern::WordSize / 8 - 1), X), [=]() -> Pattern { return Builtins::AND(X, Word(0xff)); }}, }; } @@ -191,16 +191,16 @@ std::vector> simplificationRuleListPart3( using Builtins = typename Pattern::Builtins; return std::vector> { // operations involving an expression and itself - {Builtins::AND(X, X), [=]{ return X; }, true}, - {Builtins::OR(X, X), [=]{ return X; }, true}, - {Builtins::XOR(X, X), [=]{ return Word(0); }, true}, - {Builtins::SUB(X, X), [=]{ return Word(0); }, true}, - {Builtins::EQ(X, X), [=]{ return Word(1); }, true}, - {Builtins::LT(X, X), [=]{ return Word(0); }, true}, - {Builtins::SLT(X, X), [=]{ return Word(0); }, true}, - {Builtins::GT(X, X), [=]{ return Word(0); }, true}, - {Builtins::SGT(X, X), [=]{ return Word(0); }, true}, - {Builtins::MOD(X, X), [=]{ return Word(0); }, true} + {Builtins::AND(X, X), [=]{ return X; }}, + {Builtins::OR(X, X), [=]{ return X; }}, + {Builtins::XOR(X, X), [=]{ return Word(0); }}, + {Builtins::SUB(X, X), [=]{ return Word(0); }}, + {Builtins::EQ(X, X), [=]{ return Word(1); }}, + {Builtins::LT(X, X), [=]{ return Word(0); }}, + {Builtins::SLT(X, X), [=]{ return Word(0); }}, + {Builtins::GT(X, X), [=]{ return Word(0); }}, + {Builtins::SGT(X, X), [=]{ return Word(0); }}, + {Builtins::MOD(X, X), [=]{ return Word(0); }} }; } @@ -217,23 +217,23 @@ std::vector> simplificationRuleListPart4( using Builtins = typename Pattern::Builtins; return std::vector> { // logical instruction combinations - {Builtins::NOT(Builtins::NOT(X)), [=]{ return X; }, false}, - {Builtins::XOR(X, Builtins::XOR(X, Y)), [=]{ return Y; }, true}, - {Builtins::XOR(X, Builtins::XOR(Y, X)), [=]{ return Y; }, true}, - {Builtins::XOR(Builtins::XOR(X, Y), X), [=]{ return Y; }, true}, - {Builtins::XOR(Builtins::XOR(Y, X), X), [=]{ return Y; }, true}, - {Builtins::OR(X, Builtins::AND(X, Y)), [=]{ return X; }, true}, - {Builtins::OR(X, Builtins::AND(Y, X)), [=]{ return X; }, true}, - {Builtins::OR(Builtins::AND(X, Y), X), [=]{ return X; }, true}, - {Builtins::OR(Builtins::AND(Y, X), X), [=]{ return X; }, true}, - {Builtins::AND(X, Builtins::OR(X, Y)), [=]{ return X; }, true}, - {Builtins::AND(X, Builtins::OR(Y, X)), [=]{ return X; }, true}, - {Builtins::AND(Builtins::OR(X, Y), X), [=]{ return X; }, true}, - {Builtins::AND(Builtins::OR(Y, X), X), [=]{ return X; }, true}, - {Builtins::AND(X, Builtins::NOT(X)), [=]{ return Word(0); }, true}, - {Builtins::AND(Builtins::NOT(X), X), [=]{ return Word(0); }, true}, - {Builtins::OR(X, Builtins::NOT(X)), [=]{ return ~Word(0); }, true}, - {Builtins::OR(Builtins::NOT(X), X), [=]{ return ~Word(0); }, true}, + {Builtins::NOT(Builtins::NOT(X)), [=]{ return X; }}, + {Builtins::XOR(X, Builtins::XOR(X, Y)), [=]{ return Y; }}, + {Builtins::XOR(X, Builtins::XOR(Y, X)), [=]{ return Y; }}, + {Builtins::XOR(Builtins::XOR(X, Y), X), [=]{ return Y; }}, + {Builtins::XOR(Builtins::XOR(Y, X), X), [=]{ return Y; }}, + {Builtins::OR(X, Builtins::AND(X, Y)), [=]{ return X; }}, + {Builtins::OR(X, Builtins::AND(Y, X)), [=]{ return X; }}, + {Builtins::OR(Builtins::AND(X, Y), X), [=]{ return X; }}, + {Builtins::OR(Builtins::AND(Y, X), X), [=]{ return X; }}, + {Builtins::AND(X, Builtins::OR(X, Y)), [=]{ return X; }}, + {Builtins::AND(X, Builtins::OR(Y, X)), [=]{ return X; }}, + {Builtins::AND(Builtins::OR(X, Y), X), [=]{ return X; }}, + {Builtins::AND(Builtins::OR(Y, X), X), [=]{ return X; }}, + {Builtins::AND(X, Builtins::NOT(X)), [=]{ return Word(0); }}, + {Builtins::AND(Builtins::NOT(X), X), [=]{ return Word(0); }}, + {Builtins::OR(X, Builtins::NOT(X)), [=]{ return ~Word(0); }}, + {Builtins::OR(Builtins::NOT(X), X), [=]{ return ~Word(0); }}, }; } @@ -249,14 +249,14 @@ std::vector> simplificationRuleListPart4_5( using Builtins = typename Pattern::Builtins; return std::vector>{ // idempotent operations - {Builtins::AND(Builtins::AND(X, Y), Y), [=]{ return Builtins::AND(X, Y); }, true}, - {Builtins::AND(Y, Builtins::AND(X, Y)), [=]{ return Builtins::AND(X, Y); }, true}, - {Builtins::AND(Builtins::AND(Y, X), Y), [=]{ return Builtins::AND(Y, X); }, true}, - {Builtins::AND(Y, Builtins::AND(Y, X)), [=]{ return Builtins::AND(Y, X); }, true}, - {Builtins::OR(Builtins::OR(X, Y), Y), [=]{ return Builtins::OR(X, Y); }, true}, - {Builtins::OR(Y, Builtins::OR(X, Y)), [=]{ return Builtins::OR(X, Y); }, true}, - {Builtins::OR(Builtins::OR(Y, X), Y), [=]{ return Builtins::OR(Y, X); }, true}, - {Builtins::OR(Y, Builtins::OR(Y, X)), [=]{ return Builtins::OR(Y, X); }, true}, + {Builtins::AND(Builtins::AND(X, Y), Y), [=]{ return Builtins::AND(X, Y); }}, + {Builtins::AND(Y, Builtins::AND(X, Y)), [=]{ return Builtins::AND(X, Y); }}, + {Builtins::AND(Builtins::AND(Y, X), Y), [=]{ return Builtins::AND(Y, X); }}, + {Builtins::AND(Y, Builtins::AND(Y, X)), [=]{ return Builtins::AND(Y, X); }}, + {Builtins::OR(Builtins::OR(X, Y), Y), [=]{ return Builtins::OR(X, Y); }}, + {Builtins::OR(Y, Builtins::OR(X, Y)), [=]{ return Builtins::OR(X, Y); }}, + {Builtins::OR(Builtins::OR(Y, X), Y), [=]{ return Builtins::OR(Y, X); }}, + {Builtins::OR(Y, Builtins::OR(Y, X)), [=]{ return Builtins::OR(Y, X); }}, }; } @@ -280,8 +280,7 @@ std::vector> simplificationRuleListPart5( Word value = Word(1) << i; rules.push_back({ Builtins::MOD(X, value), - [=]() -> Pattern { return Builtins::AND(X, value - 1); }, - false + [=]() -> Pattern { return Builtins::AND(X, value - 1); } }); } @@ -289,7 +288,6 @@ std::vector> simplificationRuleListPart5( rules.push_back({ Builtins::SHL(A, X), [=]() -> Pattern { return Word(0); }, - true, [=]() { return A.d() >= Pattern::WordSize; } }); @@ -297,7 +295,6 @@ std::vector> simplificationRuleListPart5( rules.push_back({ Builtins::SHR(A, X), [=]() -> Pattern { return Word(0); }, - true, [=]() { return A.d() >= Pattern::WordSize; } }); @@ -305,7 +302,6 @@ std::vector> simplificationRuleListPart5( rules.push_back({ Builtins::BYTE(A, X), [=]() -> Pattern { return Word(0); }, - true, [=]() { return A.d() >= Pattern::WordSize / 8; } }); @@ -320,13 +316,11 @@ std::vector> simplificationRuleListPart5( Word const mask = (Word(1) << 160) - 1; rules.push_back({ Builtins::AND(Pattern{instr}, mask), - [=]() -> Pattern { return {instr}; }, - false + [=]() -> Pattern { return {instr}; } }); rules.push_back({ Builtins::AND(mask, Pattern{instr}), - [=]() -> Pattern { return {instr}; }, - false + [=]() -> Pattern { return {instr}; } }); } @@ -357,21 +351,18 @@ std::vector> simplificationRuleListPart6( typename Builtins::PatternGeneratorInstance op{instr}; rules.push_back({ Builtins::ISZERO(Builtins::ISZERO(op(X, Y))), - [=]() -> Pattern { return op(X, Y); }, - false + [=]() -> Pattern { return op(X, Y); } }); } rules.push_back({ Builtins::ISZERO(Builtins::ISZERO(Builtins::ISZERO(X))), - [=]() -> Pattern { return Builtins::ISZERO(X); }, - false + [=]() -> Pattern { return Builtins::ISZERO(X); } }); rules.push_back({ Builtins::ISZERO(Builtins::XOR(X, Y)), - [=]() -> Pattern { return Builtins::EQ(X, Y); }, - false + [=]() -> Pattern { return Builtins::EQ(X, Y); } }); return rules; @@ -409,23 +400,19 @@ std::vector> simplificationRuleListPart7( rules += std::vector>{{ // (X+A)+B -> X+(A+B) op(opXA, B), - [=]() -> Pattern { return op(X, fun(A.d(), B.d())); }, - false + [=]() -> Pattern { return op(X, fun(A.d(), B.d())); } }, { // (X+A)+Y -> (X+Y)+A op(opXA, Y), - [=]() -> Pattern { return op(op(X, Y), A); }, - false + [=]() -> Pattern { return op(op(X, Y), A); } }, { // B+(X+A) -> X+(A+B) op(B, opXA), - [=]() -> Pattern { return op(X, fun(A.d(), B.d())); }, - false + [=]() -> Pattern { return op(X, fun(A.d(), B.d())); } }, { // Y+(X+A) -> (Y+X)+A op(Y, opXA), - [=]() -> Pattern { return op(op(Y, X), A); }, - false + [=]() -> Pattern { return op(op(Y, X), A); } }}; } } @@ -440,8 +427,7 @@ std::vector> simplificationRuleListPart7( return Builtins::AND(X, Word(0)); else return Builtins::SHL(Word(sum), X); - }, - false + } }); // Combine two SHR by constant @@ -454,8 +440,7 @@ std::vector> simplificationRuleListPart7( return Builtins::AND(X, Word(0)); else return Builtins::SHR(Word(sum), X); - }, - false + } }); // Combine SHL-SHR by constant @@ -472,7 +457,6 @@ std::vector> simplificationRuleListPart7( else return Builtins::AND(X, mask); }, - false, [=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; } }); @@ -490,7 +474,6 @@ std::vector> simplificationRuleListPart7( else return Builtins::AND(X, mask); }, - false, [=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; } }); @@ -509,14 +492,12 @@ std::vector> simplificationRuleListPart7( // SH[L/R](B, AND(X, A)) -> AND(SH[L/R](B, X), [ A << B / A >> B ]) shiftOp(B, Builtins::AND(X, A)), replacement, - false, [=] { return B.d() < Pattern::WordSize; } }); rules.push_back({ // SH[L/R](B, AND(A, X)) -> AND(SH[L/R](B, X), [ A << B / A >> B ]) shiftOp(B, Builtins::AND(A, X)), replacement, - false, [=] { return B.d() < Pattern::WordSize; } }); } @@ -526,17 +507,14 @@ std::vector> simplificationRuleListPart7( Builtins::MUL(X, Builtins::SHL(Y, Word(1))), [=]() -> Pattern { return Builtins::SHL(Y, X); - }, - // Actually only changes the order, does not remove. - true + } }); rules.push_back({ // MUL(SHL(X, 1), Y) -> SHL(X, Y) Builtins::MUL(Builtins::SHL(X, Word(1)), Y), [=]() -> Pattern { return Builtins::SHL(X, Y); - }, - false + } }); rules.push_back({ @@ -544,9 +522,7 @@ std::vector> simplificationRuleListPart7( Builtins::DIV(X, Builtins::SHL(Y, Word(1))), [=]() -> Pattern { return Builtins::SHR(Y, X); - }, - // Actually only changes the order, does not remove. - true + } }); std::function feasibilityFunction = [=]() { @@ -560,7 +536,6 @@ std::vector> simplificationRuleListPart7( // AND(A, SHR(B, X)) -> A & ((2^256-1) >> B) == ((2^256-1) >> B) Builtins::AND(A, Builtins::SHR(B, X)), [=]() -> Pattern { return Builtins::SHR(B, X); }, - false, feasibilityFunction }); @@ -568,28 +543,24 @@ std::vector> simplificationRuleListPart7( // AND(SHR(B, X), A) -> ((2^256-1) >> B) & A == ((2^256-1) >> B) Builtins::AND(Builtins::SHR(B, X), A), [=]() -> Pattern { return Builtins::SHR(B, X); }, - false, feasibilityFunction }); rules.push_back({ Builtins::BYTE(A, Builtins::SHL(B, X)), [=]() -> Pattern { return Builtins::BYTE(A.d() + B.d() / 8, X); }, - false, [=] { return B.d() % 8 == 0 && A.d() <= 32 && B.d() <= 256; } }); rules.push_back({ Builtins::BYTE(A, Builtins::SHR(B, X)), [=]() -> Pattern { return Word(0); }, - true, [=] { return A.d() < B.d() / 8; } }); rules.push_back({ Builtins::BYTE(A, Builtins::SHR(B, X)), [=]() -> Pattern { return Builtins::BYTE(A.d() - B.d() / 8, X); }, - false, [=] { return B.d() % 8 == 0 && A.d() < Pattern::WordSize / 8 && B.d() <= Pattern::WordSize && A.d() >= B.d() / 8; } @@ -615,76 +586,28 @@ std::vector> simplificationRuleListPart8( { // X - A -> X + (-A) Builtins::SUB(X, A), - [=]() -> Pattern { return Builtins::ADD(X, 0 - A.d()); }, - false + [=]() -> Pattern { return Builtins::ADD(X, 0 - A.d()); } }, { // (X + A) - Y -> (X - Y) + A Builtins::SUB(Builtins::ADD(X, A), Y), - [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); }, - false + [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); } }, { // (A + X) - Y -> (X - Y) + A Builtins::SUB(Builtins::ADD(A, X), Y), - [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); }, - false + [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); } }, { // X - (Y + A) -> (X - Y) + (-A) Builtins::SUB(X, Builtins::ADD(Y, A)), - [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); }, - false + [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); } }, { // X - (A + Y) -> (X - Y) + (-A) Builtins::SUB(X, Builtins::ADD(A, Y)), - [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); }, - false + [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); } } }; return rules; } -template -std::vector> simplificationRuleListPart9( - Pattern, - Pattern, - Pattern, - Pattern W, - Pattern X, - Pattern Y, - Pattern Z -) -{ - using Word = typename Pattern::Word; - using Builtins = typename Pattern::Builtins; - std::vector> rules; - - assertThrow(Pattern::WordSize > 160, OptimizerException, ""); - Word const mask = (Word(1) << 160) - 1; - // CREATE - rules.push_back({ - Builtins::AND(Builtins::CREATE(W, X, Y), mask), - [=]() -> Pattern { return Builtins::CREATE(W, X, Y); }, - false - }); - rules.push_back({ - Builtins::AND(mask, Builtins::CREATE(W, X, Y)), - [=]() -> Pattern { return Builtins::CREATE(W, X, Y); }, - false - }); - // CREATE2 - rules.push_back({ - Builtins::AND(Builtins::CREATE2(W, X, Y, Z), mask), - [=]() -> Pattern { return Builtins::CREATE2(W, X, Y, Z); }, - false - }); - rules.push_back({ - Builtins::AND(mask, Builtins::CREATE2(W, X, Y, Z)), - [=]() -> Pattern { return Builtins::CREATE2(W, X, Y, Z); }, - false - }); - - return rules; -} - template std::vector> evmRuleList( langutil::EVMVersion _evmVersion, @@ -692,20 +615,35 @@ std::vector> evmRuleList( Pattern, Pattern, Pattern, - Pattern, + Pattern X, Pattern, Pattern ) { using Builtins = typename Pattern::Builtins; + using Word = typename Pattern::Word; std::vector> rules; if (_evmVersion.hasSelfBalance()) rules.push_back({ Builtins::BALANCE(Instruction::ADDRESS), - []() -> Pattern { return Instruction::SELFBALANCE; }, false + []() -> Pattern { return Instruction::SELFBALANCE; } }); + rules.emplace_back( + Builtins::EXP(0, X), + [=]() -> Pattern { return Builtins::ISZERO(X); } + ); + rules.emplace_back( + Builtins::EXP(1, X), + [=]() -> Pattern { return Word(1); } + ); + if (_evmVersion.hasBitwiseShifting()) + rules.emplace_back( + Builtins::EXP(2, X), + [=]() -> Pattern { return Builtins::SHL(X, 1); } + ); + return rules; } @@ -743,7 +681,6 @@ std::vector> simplificationRuleList( rules += simplificationRuleListPart6(A, B, C, W, X); rules += simplificationRuleListPart7(A, B, C, W, X); rules += simplificationRuleListPart8(A, B, C, W, X); - rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z); if (_evmVersion.has_value()) rules += evmRuleList(*_evmVersion, A, B, C, W, X, Y, Z); diff --git a/libevmasm/SimplificationRule.h b/libevmasm/SimplificationRule.h index 6ce9a9e7c..b6a704a56 100644 --- a/libevmasm/SimplificationRule.h +++ b/libevmasm/SimplificationRule.h @@ -30,9 +30,8 @@ namespace solidity::evmasm /** * Rule that contains a pattern, an action that can be applied - * after the pattern has matched and a bool that indicates - * whether the action would remove something from the expression - * than is not a constant literal. + * after the pattern has matched and optional condition to check if the + * action should be applied. */ template struct SimplificationRule @@ -40,18 +39,15 @@ struct SimplificationRule SimplificationRule( Pattern _pattern, std::function _action, - bool _removesNonConstants, std::function _feasible = {} ): pattern(std::move(_pattern)), action(std::move(_action)), - removesNonConstants(_removesNonConstants), feasible(std::move(_feasible)) {} Pattern pattern; std::function action; - bool removesNonConstants; std::function feasible; }; diff --git a/libsmtutil/CHCSmtLib2Interface.cpp b/libsmtutil/CHCSmtLib2Interface.cpp index cc30c127b..bc3d1c6d9 100644 --- a/libsmtutil/CHCSmtLib2Interface.cpp +++ b/libsmtutil/CHCSmtLib2Interface.cpp @@ -50,6 +50,7 @@ void CHCSmtLib2Interface::reset() { m_accumulatedOutput.clear(); m_variables.clear(); + m_unhandledQueries.clear(); } void CHCSmtLib2Interface::registerRelation(Expression const& _expr) diff --git a/libsmtutil/CMakeLists.txt b/libsmtutil/CMakeLists.txt index 62b52f5c6..8c8b3677d 100644 --- a/libsmtutil/CMakeLists.txt +++ b/libsmtutil/CMakeLists.txt @@ -9,6 +9,7 @@ set(sources SolverInterface.h Sorts.cpp Sorts.h + Helpers.h ) if (${Z3_FOUND}) diff --git a/libsmtutil/CVC4Interface.cpp b/libsmtutil/CVC4Interface.cpp index 40526306f..ced8f184a 100644 --- a/libsmtutil/CVC4Interface.cpp +++ b/libsmtutil/CVC4Interface.cpp @@ -196,6 +196,12 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr) return m_context.mkExpr(CVC4::kind::BITVECTOR_OR, arguments[0], arguments[1]); else if (n == "bvxor") return m_context.mkExpr(CVC4::kind::BITVECTOR_XOR, arguments[0], arguments[1]); + else if (n == "bvshl") + return m_context.mkExpr(CVC4::kind::BITVECTOR_SHL, arguments[0], arguments[1]); + else if (n == "bvlshr") + return m_context.mkExpr(CVC4::kind::BITVECTOR_LSHR, arguments[0], arguments[1]); + else if (n == "bvashr") + return m_context.mkExpr(CVC4::kind::BITVECTOR_ASHR, arguments[0], arguments[1]); else if (n == "int2bv") { size_t size = std::stoul(_expr.arguments[1].name); @@ -289,6 +295,8 @@ CVC4::Type CVC4Interface::cvc4Sort(Sort const& _sort) return m_context.booleanType(); case Kind::Int: return m_context.integerType(); + case Kind::BitVector: + return m_context.mkBitVectorType(dynamic_cast(_sort).size); case Kind::Function: { FunctionSort const& fSort = dynamic_cast(_sort); diff --git a/libsmtutil/Helpers.h b/libsmtutil/Helpers.h new file mode 100644 index 000000000..feeb9a7d5 --- /dev/null +++ b/libsmtutil/Helpers.h @@ -0,0 +1,58 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +namespace solidity::smtutil +{ + +/// Signed division in SMTLIB2 rounds differently than EVM. +/// This does not check for division by zero! +inline Expression signedDivisionEVM(Expression _left, Expression _right) +{ + return Expression::ite( + _left >= 0, + Expression::ite(_right >= 0, _left / _right, 0 - (_left / (0 - _right))), + Expression::ite(_right >= 0, 0 - ((0 - _left) / _right), (0 - _left) / (0 - _right)) + ); +} + +inline Expression abs(Expression _value) +{ + return Expression::ite(_value >= 0, _value, 0 - _value); +} + +/// Signed modulo in SMTLIB2 behaves differently with regards +/// to the sign than EVM. +/// This does not check for modulo by zero! +inline Expression signedModuloEVM(Expression _left, Expression _right) +{ + return Expression::ite( + _left >= 0, + _left % _right, + Expression::ite( + (_left % _right) == 0, + 0, + (_left % _right) - abs(_right) + ) + ); +} + +} diff --git a/libsmtutil/SMTLib2Interface.cpp b/libsmtutil/SMTLib2Interface.cpp index f1d21c2cc..e1bc7d0b4 100644 --- a/libsmtutil/SMTLib2Interface.cpp +++ b/libsmtutil/SMTLib2Interface.cpp @@ -38,11 +38,11 @@ using namespace solidity::frontend; using namespace solidity::smtutil; SMTLib2Interface::SMTLib2Interface( - map const& _queryResponses, + map _queryResponses, ReadCallback::Callback _smtCallback ): - m_queryResponses(_queryResponses), - m_smtCallback(std::move(_smtCallback)) + m_queryResponses(move(_queryResponses)), + m_smtCallback(move(_smtCallback)) { reset(); } @@ -215,6 +215,8 @@ string SMTLib2Interface::toSmtLibSort(Sort const& _sort) return "Int"; case Kind::Bool: return "Bool"; + case Kind::BitVector: + return "(_ BitVec " + to_string(dynamic_cast(_sort).size) + ")"; case Kind::Array: { auto const& arraySort = dynamic_cast(_sort); diff --git a/libsmtutil/SMTLib2Interface.h b/libsmtutil/SMTLib2Interface.h index 2a43c0441..4c21b1f1c 100644 --- a/libsmtutil/SMTLib2Interface.h +++ b/libsmtutil/SMTLib2Interface.h @@ -39,8 +39,8 @@ class SMTLib2Interface: public SolverInterface, public boost::noncopyable { public: explicit SMTLib2Interface( - std::map const& _queryResponses, - frontend::ReadCallback::Callback _smtCallback + std::map _queryResponses = {}, + frontend::ReadCallback::Callback _smtCallback = {} ); void reset() override; @@ -77,7 +77,7 @@ private: std::map m_variables; std::set m_userSorts; - std::map const& m_queryResponses; + std::map m_queryResponses; std::vector m_unhandledQueries; frontend::ReadCallback::Callback m_smtCallback; diff --git a/libsmtutil/SMTPortfolio.cpp b/libsmtutil/SMTPortfolio.cpp index 334d91dd7..9858247a1 100644 --- a/libsmtutil/SMTPortfolio.cpp +++ b/libsmtutil/SMTPortfolio.cpp @@ -33,12 +33,12 @@ using namespace solidity::frontend; using namespace solidity::smtutil; SMTPortfolio::SMTPortfolio( - map const& _smtlib2Responses, - frontend::ReadCallback::Callback const& _smtCallback, + map _smtlib2Responses, + frontend::ReadCallback::Callback _smtCallback, [[maybe_unused]] SMTSolverChoice _enabledSolvers ) { - m_solvers.emplace_back(make_unique(_smtlib2Responses, _smtCallback)); + m_solvers.emplace_back(make_unique(move(_smtlib2Responses), move(_smtCallback))); #ifdef HAVE_Z3 if (_enabledSolvers.z3) m_solvers.emplace_back(make_unique()); diff --git a/libsmtutil/SMTPortfolio.h b/libsmtutil/SMTPortfolio.h index 3e933df5d..e4a662203 100644 --- a/libsmtutil/SMTPortfolio.h +++ b/libsmtutil/SMTPortfolio.h @@ -40,9 +40,9 @@ class SMTPortfolio: public SolverInterface, public boost::noncopyable { public: SMTPortfolio( - std::map const& _smtlib2Responses, - frontend::ReadCallback::Callback const& _smtCallback, - SMTSolverChoice _enabledSolvers + std::map _smtlib2Responses = {}, + frontend::ReadCallback::Callback _smtCallback = {}, + SMTSolverChoice _enabledSolvers = SMTSolverChoice::All() ); void reset() override; diff --git a/libsmtutil/SolverInterface.h b/libsmtutil/SolverInterface.h index c45ebd77b..314039260 100644 --- a/libsmtutil/SolverInterface.h +++ b/libsmtutil/SolverInterface.h @@ -99,6 +99,9 @@ public: {"bvand", 2}, {"bvor", 2}, {"bvxor", 2}, + {"bvshl", 2}, + {"bvlshr", 2}, + {"bvashr", 2}, {"int2bv", 2}, {"bv2int", 1}, {"select", 2}, @@ -299,15 +302,30 @@ public: auto bvSort = _a.sort; return Expression("bvand", {std::move(_a), std::move(_b)}, bvSort); } + friend Expression operator|(Expression _a, Expression _b) + { + auto bvSort = _a.sort; + return Expression("bvor", {std::move(_a), std::move(_b)}, bvSort); + } friend Expression operator^(Expression _a, Expression _b) { auto bvSort = _a.sort; return Expression("bvxor", {std::move(_a), std::move(_b)}, bvSort); } - friend Expression operator|(Expression _a, Expression _b) + friend Expression operator<<(Expression _a, Expression _b) { auto bvSort = _a.sort; - return Expression("bvor", {std::move(_a), std::move(_b)}, bvSort); + return Expression("bvshl", {std::move(_a), std::move(_b)}, bvSort); + } + friend Expression operator>>(Expression _a, Expression _b) + { + auto bvSort = _a.sort; + return Expression("bvlshr", {std::move(_a), std::move(_b)}, bvSort); + } + static Expression ashr(Expression _a, Expression _b) + { + auto bvSort = _a.sort; + return Expression("bvashr", {std::move(_a), std::move(_b)}, bvSort); } Expression operator()(std::vector _arguments) const { diff --git a/libsmtutil/Sorts.cpp b/libsmtutil/Sorts.cpp index 303e8bb84..543c7ba0f 100644 --- a/libsmtutil/Sorts.cpp +++ b/libsmtutil/Sorts.cpp @@ -35,4 +35,6 @@ shared_ptr SortProvider::intSort(bool _signed) return uintSort; } +shared_ptr const SortProvider::bitVectorSort{make_shared(256)}; + } diff --git a/libsmtutil/Sorts.h b/libsmtutil/Sorts.h index de94e8fff..45668f269 100644 --- a/libsmtutil/Sorts.h +++ b/libsmtutil/Sorts.h @@ -195,6 +195,7 @@ struct SortProvider static std::shared_ptr const uintSort; static std::shared_ptr const sintSort; static std::shared_ptr intSort(bool _signed = false); + static std::shared_ptr const bitVectorSort; }; } diff --git a/libsmtutil/Z3CHCInterface.cpp b/libsmtutil/Z3CHCInterface.cpp index 9ea155621..35b3556d9 100644 --- a/libsmtutil/Z3CHCInterface.cpp +++ b/libsmtutil/Z3CHCInterface.cpp @@ -95,9 +95,12 @@ pair Z3CHCInterface::query(Expression } // TODO retrieve model / invariants } - catch (z3::exception const&) + catch (z3::exception const& _err) { - result = CheckResult::ERROR; + if (_err.msg() == string("max. resource limit exceeded")) + result = CheckResult::UNKNOWN; + else + result = CheckResult::ERROR; cex = {}; } @@ -142,14 +145,17 @@ instead of a path. */ CHCSolverInterface::CexGraph Z3CHCInterface::cexGraph(z3::expr const& _proof) { - CexGraph graph; - /// The root fact of the refutation proof is `false`. /// The node itself is not a hyper resolution, so we need to /// extract the `query` hyper resolution node from the /// `false` node (the first child). - smtAssert(_proof.is_app(), ""); - smtAssert(fact(_proof).decl().decl_kind() == Z3_OP_FALSE, ""); + /// The proof has the shape above for z3 >=4.8.8. + /// If an older version is used, this check will fail and no + /// counterexample will be generated. + if (!_proof.is_app() || fact(_proof).decl().decl_kind() != Z3_OP_FALSE) + return {}; + + CexGraph graph; stack proofStack; proofStack.push(_proof.arg(0)); diff --git a/libsmtutil/Z3Interface.cpp b/libsmtutil/Z3Interface.cpp index 909a5cde2..89d378fe1 100644 --- a/libsmtutil/Z3Interface.cpp +++ b/libsmtutil/Z3Interface.cpp @@ -189,6 +189,12 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr) return arguments[0] | arguments[1]; else if (n == "bvxor") return arguments[0] ^ arguments[1]; + else if (n == "bvshl") + return z3::shl(arguments[0], arguments[1]); + else if (n == "bvlshr") + return z3::lshr(arguments[0], arguments[1]); + else if (n == "bvashr") + return z3::ashr(arguments[0], arguments[1]); else if (n == "int2bv") { size_t size = std::stoul(_expr.arguments[1].name); @@ -245,6 +251,8 @@ z3::sort Z3Interface::z3Sort(Sort const& _sort) return m_context.bool_sort(); case Kind::Int: return m_context.int_sort(); + case Kind::BitVector: + return m_context.bv_sort(dynamic_cast(_sort).size); case Kind::Array: { auto const& arraySort = dynamic_cast(_sort); diff --git a/libsmtutil/Z3Interface.h b/libsmtutil/Z3Interface.h index 23534fd75..a44bfafcd 100644 --- a/libsmtutil/Z3Interface.h +++ b/libsmtutil/Z3Interface.h @@ -49,7 +49,7 @@ public: // Z3 "basic resources" limit. // This is used to make the runs more deterministic and platform/machine independent. - static int const resourceLimit = 12500000; + static int const resourceLimit = 1000000; private: void declareFunction(std::string const& _name, Sort const& _sort); diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 5e823d8ee..091c87cd4 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -30,6 +30,8 @@ set(sources analysis/PostTypeChecker.h analysis/ReferencesResolver.cpp analysis/ReferencesResolver.h + analysis/Scoper.cpp + analysis/Scoper.h analysis/StaticAnalyzer.cpp analysis/StaticAnalyzer.h analysis/SyntaxChecker.cpp @@ -102,6 +104,8 @@ set(sources formal/ModelChecker.h formal/Predicate.cpp formal/Predicate.h + formal/PredicateSort.cpp + formal/PredicateSort.h formal/SMTEncoder.cpp formal/SMTEncoder.h formal/SSAVariable.cpp diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index ff6b30e79..47f9af62a 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -38,19 +38,51 @@ namespace { template -bool hasEqualNameAndParameters(T const& _a, B const& _b) +bool hasEqualParameters(T const& _a, B const& _b) { - return - _a.name() == _b.name() && - FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes( - *FunctionType(_b).asExternallyCallableFunction(false) - ); + return FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes( + *FunctionType(_b).asExternallyCallableFunction(false) + ); } +template +map> filterDeclarations( + map> const& _declarations) +{ + map> filteredDeclarations; + for (auto const& [name, overloads]: _declarations) + for (auto const* declaration: overloads) + if (auto typedDeclaration = dynamic_cast(declaration)) + filteredDeclarations[name].push_back(typedDeclaration); + return filteredDeclarations; +} + +} + +bool ContractLevelChecker::check(SourceUnit const& _sourceUnit) +{ + bool noErrors = true; + findDuplicateDefinitions( + filterDeclarations(*_sourceUnit.annotation().exportedSymbols) + ); + // This check flags duplicate free events when free events become + // a Solidity feature + findDuplicateDefinitions( + filterDeclarations(*_sourceUnit.annotation().exportedSymbols) + ); + if (!Error::containsOnlyWarnings(m_errorReporter.errors())) + noErrors = false; + for (ASTPointer const& node: _sourceUnit.nodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + if (!check(*contract)) + noErrors = false; + return noErrors; } bool ContractLevelChecker::check(ContractDefinition const& _contract) { + _contract.annotation().unimplementedDeclarations = std::vector(); + checkDuplicateFunctions(_contract); checkDuplicateEvents(_contract); m_overrideChecker.check(_contract); @@ -141,8 +173,21 @@ void ContractLevelChecker::findDuplicateDefinitions(map> const SecondarySourceLocation ssl; for (size_t j = i + 1; j < overloads.size(); ++j) - if (hasEqualNameAndParameters(*overloads[i], *overloads[j])) + if (hasEqualParameters(*overloads[i], *overloads[j])) { + solAssert( + ( + dynamic_cast(overloads[i]->scope()) && + dynamic_cast(overloads[j]->scope()) && + overloads[i]->name() == overloads[j]->name() + ) || + ( + dynamic_cast(overloads[i]->scope()) && + dynamic_cast(overloads[j]->scope()) + ), + "Override is neither a namesake function/event in contract scope nor " + "a free function/event (alias)." + ); ssl.append("Other declaration is here:", overloads[j]->location()); reported.insert(j); } @@ -210,9 +255,10 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c // Set to not fully implemented if at least one flag is false. // Note that `_contract.annotation().unimplementedDeclarations` has already been // pre-filled by `checkBaseConstructorArguments`. + // for (auto const& proxy: proxies) if (proxy.unimplemented()) - _contract.annotation().unimplementedDeclarations.push_back(proxy.declaration()); + _contract.annotation().unimplementedDeclarations->push_back(proxy.declaration()); if (_contract.abstract()) { @@ -229,17 +275,17 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c if ( _contract.contractKind() == ContractKind::Contract && !_contract.abstract() && - !_contract.annotation().unimplementedDeclarations.empty() + !_contract.annotation().unimplementedDeclarations->empty() ) { SecondarySourceLocation ssl; - for (auto declaration: _contract.annotation().unimplementedDeclarations) + for (auto declaration: *_contract.annotation().unimplementedDeclarations) ssl.append("Missing implementation: ", declaration->location()); m_errorReporter.typeError( 3656_error, _contract.location(), ssl, - "Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract." + "Contract \"" + *_contract.annotation().canonicalName + "\" should be marked as abstract." ); } } @@ -289,7 +335,7 @@ void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition cons if (FunctionDefinition const* constructor = contract->constructor()) if (contract != &_contract && !constructor->parameters().empty()) if (!_contract.annotation().baseConstructorArguments.count(constructor)) - _contract.annotation().unimplementedDeclarations.push_back(constructor); + _contract.annotation().unimplementedDeclarations->push_back(constructor); } void ContractLevelChecker::annotateBaseConstructorArguments( @@ -465,7 +511,6 @@ void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition void ContractLevelChecker::checkStorageSize(ContractDefinition const& _contract) { bigint size = 0; - vector variables; for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts)) for (VariableDeclaration const* variable: contract->stateVariables()) if (!(variable->isConstant() || variable->immutable())) @@ -473,7 +518,7 @@ void ContractLevelChecker::checkStorageSize(ContractDefinition const& _contract) size += variable->annotation().type->storageSizeUpperBound(); if (size >= bigint(1) << 256) { - m_errorReporter.typeError(7676_error, _contract.location(), "Contract too large for storage."); + m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage."); break; } } diff --git a/libsolidity/analysis/ContractLevelChecker.h b/libsolidity/analysis/ContractLevelChecker.h index 2af0963d7..5f890681a 100644 --- a/libsolidity/analysis/ContractLevelChecker.h +++ b/libsolidity/analysis/ContractLevelChecker.h @@ -39,7 +39,7 @@ namespace solidity::frontend /** * Component that verifies overloads, abstract contracts, function clashes and others - * checks at contract or function level. + * checks at file, contract, or function level. */ class ContractLevelChecker { @@ -51,11 +51,14 @@ public: m_errorReporter(_errorReporter) {} + /// Performs checks on the given source ast. + /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings + bool check(SourceUnit const& _sourceUnit); + +private: /// Performs checks on the given contract. /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings bool check(ContractDefinition const& _contract); - -private: /// Checks that two functions defined in this contract with the same name have different /// arguments and that there is at most one constructor. void checkDuplicateFunctions(ContractDefinition const& _contract); diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index 93f676c6f..2cf34ae6d 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -167,7 +167,7 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va // If this is not an ordinary assignment, we write and read at the same time. bool write = _expression.annotation().willBeWrittenTo; - bool read = !_expression.annotation().willBeWrittenTo || !_expression.annotation().lValueOfOrdinaryAssignment; + bool read = !_expression.annotation().willBeWrittenTo || !*_expression.annotation().lValueOfOrdinaryAssignment; if (write) { if (!m_currentConstructor) diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 957046810..00f8f8188 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -74,7 +74,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map(node.get())) { - string const& path = imp->annotation().absolutePath; + string const& path = *imp->annotation().absolutePath; if (!_sourceUnits.count(path)) { m_errorReporter.declarationError( @@ -121,6 +121,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, mapdeclarations(); return !error; } @@ -503,11 +504,20 @@ bool DeclarationRegistrationHelper::registerDeclaration( else { auto shadowedLocation = shadowedDeclaration->location(); - _errorReporter.warning( - 2519_error, - _declaration.location(), - "This declaration shadows an existing declaration.", - SecondarySourceLocation().append("The shadowed declaration is here:", shadowedLocation) + + if (!shadowedDeclaration->isVisibleInContract()) + _errorReporter.warning( + 8760_error, + _declaration.location(), + "This declaration has the same name as another declaration.", + SecondarySourceLocation().append("The other declaration is here:", shadowedLocation) + ); + else + _errorReporter.warning( + 2519_error, + _declaration.location(), + "This declaration shadows an existing declaration.", + SecondarySourceLocation().append("The shadowed declaration is here:", shadowedLocation) ); } } @@ -519,14 +529,12 @@ bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit) if (!m_scopes[&_sourceUnit]) // By importing, it is possible that the container already exists. m_scopes[&_sourceUnit] = make_shared(m_currentScope, m_scopes[m_currentScope].get()); - m_currentScope = &_sourceUnit; - return true; + return ASTVisitor::visit(_sourceUnit); } void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit) { - _sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations(); - closeCurrentScope(); + ASTVisitor::endVisit(_sourceUnit); } bool DeclarationRegistrationHelper::visit(ImportDirective& _import) @@ -536,8 +544,7 @@ bool DeclarationRegistrationHelper::visit(ImportDirective& _import) if (!m_scopes[importee]) m_scopes[importee] = make_shared(nullptr, m_scopes[nullptr].get()); m_scopes[&_import] = m_scopes[importee]; - registerDeclaration(_import, false); - return true; + return ASTVisitor::visit(_import); } bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract) @@ -547,122 +554,17 @@ bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract) m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, false, true); m_currentContract = &_contract; - registerDeclaration(_contract, true); - _contract.annotation().canonicalName = currentCanonicalName(); - return true; + return ASTVisitor::visit(_contract); } -void DeclarationRegistrationHelper::endVisit(ContractDefinition&) +void DeclarationRegistrationHelper::endVisit(ContractDefinition& _contract) { // make "this" and "super" invisible. m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentThis(), nullptr, true, true); m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, true, true); m_globalContext.resetCurrentContract(); m_currentContract = nullptr; - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(StructDefinition& _struct) -{ - registerDeclaration(_struct, true); - _struct.annotation().canonicalName = currentCanonicalName(); - return true; -} - -void DeclarationRegistrationHelper::endVisit(StructDefinition&) -{ - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(EnumDefinition& _enum) -{ - registerDeclaration(_enum, true); - _enum.annotation().canonicalName = currentCanonicalName(); - return true; -} - -void DeclarationRegistrationHelper::endVisit(EnumDefinition&) -{ - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(EnumValue& _value) -{ - registerDeclaration(_value, false); - return true; -} - -bool DeclarationRegistrationHelper::visit(FunctionDefinition& _function) -{ - registerDeclaration(_function, true); - m_currentFunction = &_function; - return true; -} - -void DeclarationRegistrationHelper::endVisit(FunctionDefinition&) -{ - m_currentFunction = nullptr; - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause) -{ - _tryCatchClause.annotation().scope = m_currentScope; - enterNewSubScope(_tryCatchClause); - return true; -} - -void DeclarationRegistrationHelper::endVisit(TryCatchClause&) -{ - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(ModifierDefinition& _modifier) -{ - registerDeclaration(_modifier, true); - m_currentFunction = &_modifier; - return true; -} - -void DeclarationRegistrationHelper::endVisit(ModifierDefinition&) -{ - m_currentFunction = nullptr; - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(FunctionTypeName& _funTypeName) -{ - enterNewSubScope(_funTypeName); - return true; -} - -void DeclarationRegistrationHelper::endVisit(FunctionTypeName&) -{ - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(Block& _block) -{ - _block.annotation().scope = m_currentScope; - enterNewSubScope(_block); - return true; -} - -void DeclarationRegistrationHelper::endVisit(Block&) -{ - closeCurrentScope(); -} - -bool DeclarationRegistrationHelper::visit(ForStatement& _for) -{ - _for.annotation().scope = m_currentScope; - enterNewSubScope(_for); - return true; -} - -void DeclarationRegistrationHelper::endVisit(ForStatement&) -{ - closeCurrentScope(); + ASTVisitor::endVisit(_contract); } void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) @@ -673,32 +575,42 @@ void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _vari for (ASTPointer const& var: _variableDeclarationStatement.declarations()) if (var) m_currentFunction->addLocalVariable(*var); + ASTVisitor::endVisit(_variableDeclarationStatement); } -bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) +bool DeclarationRegistrationHelper::visitNode(ASTNode& _node) { - registerDeclaration(_declaration, false); + if (auto const* scopable = dynamic_cast(&_node)) + solAssert(scopable->annotation().scope == m_currentScope, ""); + + if (auto* declaration = dynamic_cast(&_node)) + registerDeclaration(*declaration); + if (dynamic_cast(&_node)) + enterNewSubScope(_node); + + if (auto* variableScope = dynamic_cast(&_node)) + m_currentFunction = variableScope; + if (auto* annotation = dynamic_cast(&_node.annotation())) + annotation->canonicalName = currentCanonicalName(); + return true; } -bool DeclarationRegistrationHelper::visit(EventDefinition& _event) +void DeclarationRegistrationHelper::endVisitNode(ASTNode& _node) { - registerDeclaration(_event, true); - return true; -} - -void DeclarationRegistrationHelper::endVisit(EventDefinition&) -{ - closeCurrentScope(); + if (dynamic_cast(&_node)) + closeCurrentScope(); + if (dynamic_cast(&_node)) + m_currentFunction = nullptr; } void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope) { - map>::iterator iter; - bool newlyAdded; shared_ptr container{make_shared(m_currentScope, m_scopes[m_currentScope].get())}; - tie(iter, newlyAdded) = m_scopes.emplace(&_subScope, move(container)); - solAssert(newlyAdded, "Unable to add new scope."); + bool newlyAdded = m_scopes.emplace(&_subScope, move(container)).second; + // Source units are the only AST nodes for which containers can be created from multiple places + // due to imports. + solAssert(newlyAdded || dynamic_cast(&_subScope), "Unable to add new scope."); m_currentScope = &_subScope; } @@ -708,7 +620,7 @@ void DeclarationRegistrationHelper::closeCurrentScope() m_currentScope = m_scopes[m_currentScope]->enclosingNode(); } -void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) +void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration) { solAssert(m_currentScope && m_scopes.count(m_currentScope), "No current scope."); @@ -729,10 +641,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter); - _declaration.annotation().scope = m_currentScope; - _declaration.annotation().contract = m_currentContract; - if (_opensScope) - enterNewSubScope(_declaration); + solAssert(_declaration.annotation().scope == m_currentScope, ""); + solAssert(_declaration.annotation().contract == m_currentContract, ""); } string DeclarationRegistrationHelper::currentCanonicalName() const diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index d72822653..a5a178a83 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -163,31 +163,15 @@ private: bool visit(ImportDirective& _import) override; bool visit(ContractDefinition& _contract) override; void endVisit(ContractDefinition& _contract) override; - bool visit(StructDefinition& _struct) override; - void endVisit(StructDefinition& _struct) override; - bool visit(EnumDefinition& _enum) override; - void endVisit(EnumDefinition& _enum) override; - bool visit(EnumValue& _value) override; - bool visit(FunctionDefinition& _function) override; - void endVisit(FunctionDefinition& _function) override; - bool visit(TryCatchClause& _tryCatchClause) override; - void endVisit(TryCatchClause& _tryCatchClause) override; - bool visit(ModifierDefinition& _modifier) override; - void endVisit(ModifierDefinition& _modifier) override; - bool visit(FunctionTypeName& _funTypeName) override; - void endVisit(FunctionTypeName& _funTypeName) override; - bool visit(Block& _block) override; - void endVisit(Block& _block) override; - bool visit(ForStatement& _forLoop) override; - void endVisit(ForStatement& _forLoop) override; void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; - bool visit(VariableDeclaration& _declaration) override; - bool visit(EventDefinition& _event) override; - void endVisit(EventDefinition& _event) override; + + bool visitNode(ASTNode& _node) override; + void endVisitNode(ASTNode& _node) override; + void enterNewSubScope(ASTNode& _subScope); void closeCurrentScope(); - void registerDeclaration(Declaration& _declaration, bool _opensScope); + void registerDeclaration(Declaration& _declaration); static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2); diff --git a/libsolidity/analysis/Scoper.cpp b/libsolidity/analysis/Scoper.cpp new file mode 100644 index 000000000..98716cf0f --- /dev/null +++ b/libsolidity/analysis/Scoper.cpp @@ -0,0 +1,63 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::frontend; + +void Scoper::assignScopes(ASTNode const& _astRoot) +{ + Scoper scoper; + _astRoot.accept(scoper); +} + +bool Scoper::visit(ContractDefinition const& _contract) +{ + solAssert(m_contract == nullptr, ""); + m_contract = &_contract; + return ASTConstVisitor::visit(_contract); +} + +void Scoper::endVisit(ContractDefinition const& _contract) +{ + solAssert(m_contract == &_contract, ""); + m_contract = nullptr; + ASTConstVisitor::endVisit(_contract); +} + +bool Scoper::visitNode(ASTNode const& _node) +{ + if (auto const* scopable = dynamic_cast(&_node)) + { + scopable->annotation().scope = m_scopes.empty() ? nullptr : m_scopes.back(); + scopable->annotation().contract = m_contract; + } + if (dynamic_cast(&_node)) + m_scopes.push_back(&_node); + return true; +} + +void Scoper::endVisitNode(ASTNode const& _node) +{ + if (dynamic_cast(&_node)) + m_scopes.pop_back(); +} diff --git a/test/libsolidity/SMTCheckerJSONTest.h b/libsolidity/analysis/Scoper.h similarity index 50% rename from test/libsolidity/SMTCheckerJSONTest.h rename to libsolidity/analysis/Scoper.h index 6de7f36c9..c55e58040 100644 --- a/test/libsolidity/SMTCheckerJSONTest.h +++ b/libsolidity/analysis/Scoper.h @@ -18,31 +18,28 @@ #pragma once -#include +#include +#include -#include - -#include - -namespace solidity::frontend::test +namespace solidity::frontend { -class SMTCheckerJSONTest: public SyntaxTest +/** + * AST visitor that assigns syntactic scopes. + */ +class Scoper: private ASTConstVisitor { public: - static std::unique_ptr create(Config const& _config) - { - return std::make_unique(_config.filename, _config.evmVersion); - } - SMTCheckerJSONTest(std::string const& _filename, langutil::EVMVersion _evmVersion); - - TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; + static void assignScopes(ASTNode const& _astRoot); private: - std::vector hashesFromJson(Json::Value const& _jsonObj, std::string const& _auxInput, std::string const& _smtlib); - Json::Value buildJson(std::string const& _extra); + bool visit(ContractDefinition const& _contract) override; + void endVisit(ContractDefinition const& _contract) override; + bool visitNode(ASTNode const& _node) override; + void endVisitNode(ASTNode const& _node) override; - Json::Value m_smtResponses; + ContractDefinition const* m_contract = nullptr; + std::vector m_scopes; }; } diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index a6d797910..abfeae23d 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -156,6 +156,19 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable) // This is not a no-op, the entry might pre-exist. m_localVarUseCount[make_pair(_variable.id(), &_variable)] += 0; } + + if (_variable.isStateVariable() || _variable.referenceLocation() == VariableDeclaration::Location::Storage) + if (auto varType = dynamic_cast(_variable.annotation().type)) + for (Type const* type: varType->fullDecomposition()) + if (type->storageSizeUpperBound() >= (bigint(1) << 64)) + { + string message = "Type " + type->toString(true) + + " 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" + " in small quantities per transaction."; + m_errorReporter.warning(7325_error, _variable.typeName().location(), message); + } + return true; } @@ -172,7 +185,7 @@ bool StaticAnalyzer::visit(Return const& _return) bool StaticAnalyzer::visit(ExpressionStatement const& _statement) { - if (_statement.expression().annotation().isPure) + if (*_statement.expression().annotation().isPure) m_errorReporter.warning( 6133_error, _statement.location(), @@ -274,7 +287,7 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly) bool StaticAnalyzer::visit(BinaryOperation const& _operation) { if ( - _operation.rightExpression().annotation().isPure && + *_operation.rightExpression().annotation().isPure && (_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod) ) if (auto rhs = dynamic_cast( @@ -299,7 +312,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall) if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod) { solAssert(_functionCall.arguments().size() == 3, ""); - if (_functionCall.arguments()[2]->annotation().isPure) + if (*_functionCall.arguments()[2]->annotation().isPure) if (auto lastArg = dynamic_cast( ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2]) )) diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 670939321..076592053 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -219,11 +219,12 @@ bool SyntaxChecker::visit(Throw const& _throwStatement) bool SyntaxChecker::visit(Literal const& _literal) { - if ((_literal.token() == Token::UnicodeStringLiteral) && !validateUTF8(_literal.value())) + size_t invalidSequence; + if ((_literal.token() == Token::UnicodeStringLiteral) && !validateUTF8(_literal.value(), invalidSequence)) m_errorReporter.syntaxError( 8452_error, _literal.location(), - "Invalid UTF-8 sequence found" + "Contains invalid UTF-8 sequence at position " + toString(invalidSequence) + "." ); if (_literal.token() != Token::Number) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 990192d68..b81e3844a 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -320,6 +320,15 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) void TypeChecker::endVisit(ModifierDefinition const& _modifier) { + if (_modifier.virtualSemantics()) + if (auto const* contractDef = dynamic_cast(_modifier.scope())) + if (contractDef->isLibrary()) + m_errorReporter.typeError( + 3275_error, + _modifier.location(), + "Modifiers in a library cannot be virtual." + ); + if (!_modifier.isImplemented() && !_modifier.virtualSemantics()) m_errorReporter.typeError(8063_error, _modifier.location(), "Modifiers without implementation must be marked virtual."); } @@ -529,7 +538,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (!_variable.value()) m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable."); - else if (!_variable.value()->annotation().isPure) + else if (!*_variable.value()->annotation().isPure) m_errorReporter.typeError( 8349_error, _variable.value()->location(), @@ -600,29 +609,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) } } - if (varType->dataStoredIn(DataLocation::Storage)) - { - auto collisionMessage = [&](string const& variableOrType, bool isVariable) -> string { - return - (isVariable ? "Variable " : "Type ") + - util::escapeAndQuoteString(variableOrType) + - " 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" - " in small quantities per transaction."; - }; - - if (varType->storageSizeUpperBound() >= bigint(1) << 64) - { - if (_variable.isStateVariable()) - m_errorReporter.warning(3408_error, _variable.location(), collisionMessage(_variable.name(), true)); - else - m_errorReporter.warning(2332_error, _variable.typeName().location(), collisionMessage(varType->toString(true), false)); - } - vector oversizedSubtypes = frontend::oversizedSubtypes(*varType); - for (Type const* subtype: oversizedSubtypes) - m_errorReporter.warning(7325_error, _variable.typeName().location(), collisionMessage(subtype->canonicalName(), false)); - } - return false; } @@ -1310,11 +1296,14 @@ bool TypeChecker::visit(Conditional const& _conditional) } } + _conditional.annotation().isConstant = false; _conditional.annotation().type = commonType; _conditional.annotation().isPure = - _conditional.condition().annotation().isPure && - _conditional.trueExpression().annotation().isPure && - _conditional.falseExpression().annotation().isPure; + *_conditional.condition().annotation().isPure && + *_conditional.trueExpression().annotation().isPure && + *_conditional.falseExpression().annotation().isPure; + + _conditional.annotation().isLValue = false; if (_conditional.annotation().willBeWrittenTo) m_errorReporter.typeError( @@ -1368,6 +1357,9 @@ bool TypeChecker::visit(Assignment const& _assignment) ); TypePointer t = type(_assignment.leftHandSide()); _assignment.annotation().type = t; + _assignment.annotation().isPure = false; + _assignment.annotation().isLValue = false; + _assignment.annotation().isConstant = false; checkExpressionAssignment(*t, _assignment.leftHandSide()); @@ -1415,6 +1407,7 @@ bool TypeChecker::visit(Assignment const& _assignment) bool TypeChecker::visit(TupleExpression const& _tuple) { + _tuple.annotation().isConstant = false; vector> const& components = _tuple.components(); TypePointers types; @@ -1427,7 +1420,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) { requireLValue( *component, - _tuple.annotation().lValueOfOrdinaryAssignment + *_tuple.annotation().lValueOfOrdinaryAssignment ); types.push_back(type(*component)); } @@ -1439,6 +1432,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) _tuple.annotation().type = TypeProvider::tuple(move(types)); // If some of the components are not LValues, the error is reported above. _tuple.annotation().isLValue = true; + _tuple.annotation().isPure = false; } else { @@ -1478,7 +1472,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) else if (inlineArrayType) inlineArrayType = Type::commonType(inlineArrayType, types[i]); } - if (!components[i]->annotation().isPure) + if (!*components[i]->annotation().isPure) isPure = false; } _tuple.annotation().isPure = isPure; @@ -1509,6 +1503,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) _tuple.annotation().type = TypeProvider::tuple(move(types)); } + _tuple.annotation().isLValue = false; } return false; } @@ -1536,7 +1531,9 @@ bool TypeChecker::visit(UnaryOperation const& _operation) t = subExprType; } _operation.annotation().type = t; - _operation.annotation().isPure = !modifying && _operation.subExpression().annotation().isPure; + _operation.annotation().isConstant = false; + _operation.annotation().isPure = !modifying && *_operation.subExpression().annotation().isPure; + _operation.annotation().isLValue = false; return false; } @@ -1567,8 +1564,10 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) TypeProvider::boolean() : commonType; _operation.annotation().isPure = - _operation.leftExpression().annotation().isPure && - _operation.rightExpression().annotation().isPure; + *_operation.leftExpression().annotation().isPure && + *_operation.rightExpression().annotation().isPure; + _operation.annotation().isLValue = false; + _operation.annotation().isConstant = false; if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL) { @@ -1646,7 +1645,8 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( dataLoc = argRefType->location(); if (auto type = dynamic_cast(resultType)) resultType = TypeProvider::withLocation(type, dataLoc, type->isPointer()); - if (argType->isExplicitlyConvertibleTo(*resultType)) + BoolResult result = argType->isExplicitlyConvertibleTo(*resultType); + if (result) { if (auto argArrayType = dynamic_cast(argType)) { @@ -1717,14 +1717,15 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( "you can use the .address member of the function." ); else - m_errorReporter.typeError( + m_errorReporter.typeErrorConcatenateDescriptions( 9640_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + argType->toString() + "\" to \"" + resultType->toString() + - "\"." + "\".", + result.message() ); } if (auto addressType = dynamic_cast(resultType)) @@ -2105,18 +2106,17 @@ void TypeChecker::typeCheckFunctionGeneralChecks( { bool not_all_mapped = false; - for (size_t i = 0; i < paramArgMap.size(); i++) + for (size_t i = 0; i < argumentNames.size(); i++) { size_t j; - for (j = 0; j < argumentNames.size(); j++) - if (parameterNames[i] == *argumentNames[j]) + for (j = 0; j < parameterNames.size(); j++) + if (parameterNames[j] == *argumentNames[i]) break; - if (j < argumentNames.size()) - paramArgMap[i] = arguments[j].get(); + if (j < parameterNames.size()) + paramArgMap[j] = arguments[i].get(); else { - paramArgMap[i] = nullptr; not_all_mapped = true; m_errorReporter.typeError( 4974_error, @@ -2189,7 +2189,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) for (ASTPointer const& argument: arguments) { argument->accept(*this); - if (!argument->annotation().isPure) + if (!*argument->annotation().isPure) argumentsArePure = false; } @@ -2212,6 +2212,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) // Determine function call kind and function type for this FunctionCall node FunctionCallAnnotation& funcCallAnno = _functionCall.annotation(); FunctionTypePointer functionType = nullptr; + funcCallAnno.isConstant = false; + + bool isLValue = false; // Determine and assign function call kind, lvalue, purity and function type for this FunctionCall node switch (expressionType->category()) @@ -2223,7 +2226,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) // Purity for function calls also depends upon the callee and its FunctionType funcCallAnno.isPure = argumentsArePure && - _functionCall.expression().annotation().isPure && + *_functionCall.expression().annotation().isPure && functionType && functionType->isPure(); @@ -2231,7 +2234,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) functionType->kind() == FunctionType::Kind::ArrayPush || functionType->kind() == FunctionType::Kind::ByteArrayPush ) - funcCallAnno.isLValue = functionType->parameterTypes().empty(); + isLValue = functionType->parameterTypes().empty(); break; @@ -2251,13 +2254,11 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) ); functionType = dynamic_cast(*actualType).constructorType(); funcCallAnno.kind = FunctionCallKind::StructConstructorCall; - funcCallAnno.isPure = argumentsArePure; } else - { funcCallAnno.kind = FunctionCallKind::TypeConversion; - funcCallAnno.isPure = argumentsArePure; - } + + funcCallAnno.isPure = argumentsArePure; break; } @@ -2270,6 +2271,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) break; } + funcCallAnno.isLValue = isLValue; + // Determine return types switch (*funcCallAnno.kind) { @@ -2340,6 +2343,9 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) _functionCallOptions.expression().accept(*this); + _functionCallOptions.annotation().isPure = false; + _functionCallOptions.annotation().isConstant = false; + auto expressionFunctionType = dynamic_cast(type(_functionCallOptions.expression())); if (!expressionFunctionType) { @@ -2470,6 +2476,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) TypePointer type = _newExpression.typeName().annotation().type; solAssert(!!type, "Type name not resolved."); + _newExpression.annotation().isConstant = false; + if (auto contractName = dynamic_cast(&_newExpression.typeName())) { auto contract = dynamic_cast(&dereference(*contractName)); @@ -2500,6 +2508,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) } _newExpression.annotation().type = FunctionType::newExpressionType(*contract); + _newExpression.annotation().isPure = false; } else if (type->category() == Type::Category::Array) { @@ -2556,6 +2565,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) auto& annotation = _memberAccess.annotation(); + annotation.isConstant = false; + if (possibleMembers.empty()) { if (initialMemberCount == 0 && !dynamic_cast(exprType)) @@ -2688,11 +2699,16 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) functionType && functionType->kind() == FunctionType::Kind::Declaration ) - annotation.isPure = _memberAccess.expression().annotation().isPure; + annotation.isPure = *_memberAccess.expression().annotation().isPure; } } else if (exprType->category() == Type::Category::Module) - annotation.isPure = _memberAccess.expression().annotation().isPure; + { + annotation.isPure = *_memberAccess.expression().annotation().isPure; + annotation.isLValue = false; + } + else + annotation.isLValue = false; // TODO some members might be pure, but for example `address(0x123).balance` is not pure // although every subexpression is, so leaving this limited for now. @@ -2708,11 +2724,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ) if (auto const* parentAccess = dynamic_cast(&_memberAccess.expression())) { - annotation.isPure = parentAccess->expression().annotation().isPure; + bool isPure = *parentAccess->expression().annotation().isPure; if (auto const* exprInt = dynamic_cast(&parentAccess->expression())) if (exprInt->name() == "this" || exprInt->name() == "super") - annotation.isPure = true; + isPure = true; + + annotation.isPure = isPure; } + if (auto magicType = dynamic_cast(exprType)) { if (magicType->kind() == MagicType::Kind::ABI) @@ -2760,16 +2779,20 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.isPure = true; } + if (!annotation.isPure.set()) + annotation.isPure = false; + return false; } bool TypeChecker::visit(IndexAccess const& _access) { + _access.annotation().isConstant = false; _access.baseExpression().accept(*this); TypePointer baseType = type(_access.baseExpression()); TypePointer resultType = nullptr; bool isLValue = false; - bool isPure = _access.baseExpression().annotation().isPure; + bool isPure = *_access.baseExpression().annotation().isPure; Expression const* index = _access.indexExpression(); switch (baseType->category()) { @@ -2871,7 +2894,7 @@ bool TypeChecker::visit(IndexAccess const& _access) } _access.annotation().type = resultType; _access.annotation().isLValue = isLValue; - if (index && !index->annotation().isPure) + if (index && !*index->annotation().isPure) isPure = false; _access.annotation().isPure = isPure; @@ -2880,24 +2903,28 @@ bool TypeChecker::visit(IndexAccess const& _access) bool TypeChecker::visit(IndexRangeAccess const& _access) { + _access.annotation().isConstant = false; _access.baseExpression().accept(*this); bool isLValue = false; // TODO: set this correctly when implementing slices for memory and storage arrays - bool isPure = _access.baseExpression().annotation().isPure; + bool isPure = *_access.baseExpression().annotation().isPure; if (Expression const* start = _access.startExpression()) { expectType(*start, *TypeProvider::uint256()); - if (!start->annotation().isPure) + if (!*start->annotation().isPure) isPure = false; } if (Expression const* end = _access.endExpression()) { expectType(*end, *TypeProvider::uint256()); - if (!end->annotation().isPure) + if (!*end->annotation().isPure) isPure = false; } + _access.annotation().isLValue = isLValue; + _access.annotation().isPure = isPure; + TypePointer exprType = type(_access.baseExpression()); if (exprType->category() == Type::Category::TypeType) { @@ -2912,14 +2939,11 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) else if (!(arrayType = dynamic_cast(exprType))) 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(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays."); else if (arrayType->baseType()->isDynamicallyEncoded()) m_errorReporter.typeError(2148_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; return false; } @@ -3037,20 +3061,22 @@ bool TypeChecker::visit(Identifier const& _identifier) !!annotation.referencedDeclaration, "Referenced declaration is null after overload resolution." ); + bool isConstant = false; annotation.isLValue = annotation.referencedDeclaration->isLValue(); annotation.type = annotation.referencedDeclaration->type(); solAssert(annotation.type, "Declaration referenced before type could be determined."); if (auto variableDeclaration = dynamic_cast(annotation.referencedDeclaration)) - annotation.isPure = annotation.isConstant = variableDeclaration->isConstant(); + annotation.isPure = isConstant = variableDeclaration->isConstant(); else if (dynamic_cast(annotation.referencedDeclaration)) - { - if (dynamic_cast(annotation.type)) - annotation.isPure = true; - } + annotation.isPure = dynamic_cast(annotation.type); else if (dynamic_cast(annotation.type)) annotation.isPure = true; else if (dynamic_cast(annotation.type)) annotation.isPure = true; + else + annotation.isPure = false; + + annotation.isConstant = isConstant; // Check for deprecated function names. // The check is done here for the case without an actual function call. @@ -3091,6 +3117,8 @@ void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr) { _expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.type().typeName(), _expr.type().stateMutability())); _expr.annotation().isPure = true; + _expr.annotation().isLValue = false; + _expr.annotation().isConstant = false; } void TypeChecker::endVisit(Literal const& _literal) @@ -3146,6 +3174,8 @@ void TypeChecker::endVisit(Literal const& _literal) m_errorReporter.fatalTypeError(2826_error, _literal.location(), "Invalid literal value."); _literal.annotation().isPure = true; + _literal.annotation().isLValue = false; + _literal.annotation().isConstant = false; } void TypeChecker::endVisit(UsingForDirective const& _usingFor) @@ -3189,7 +3219,8 @@ Declaration const& TypeChecker::dereference(UserDefinedTypeName const& _typeName bool TypeChecker::expectType(Expression const& _expression, Type const& _expectedType) { _expression.accept(*this); - if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType)) + BoolResult result = type(_expression)->isImplicitlyConvertibleTo(_expectedType); + if (!result) { auto errorMsg = "Type " + type(_expression)->toString() + @@ -3208,17 +3239,23 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte errorMsg + ", but it can be explicitly converted." ); else - m_errorReporter.typeError( + m_errorReporter.typeErrorConcatenateDescriptions( 2326_error, _expression.location(), errorMsg + ". Try converting to type " + type(_expression)->mobileType()->toString() + - " or use an explicit conversion." + " or use an explicit conversion.", + result.message() ); } else - m_errorReporter.typeError(7407_error, _expression.location(), errorMsg + "."); + m_errorReporter.typeErrorConcatenateDescriptions( + 7407_error, + _expression.location(), + errorMsg + ".", + result.message() + ); return false; } return true; @@ -3230,11 +3267,11 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss _expression.annotation().lValueOfOrdinaryAssignment = _ordinaryAssignment; _expression.accept(*this); - if (_expression.annotation().isLValue) + if (*_expression.annotation().isLValue) return; auto [errorId, description] = [&]() -> tuple { - if (_expression.annotation().isConstant) + if (*_expression.annotation().isConstant) return { 6520_error, "Cannot assign to a constant variable." }; if (auto indexAccess = dynamic_cast(&_expression)) diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index b75b4a240..f684bc289 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -261,21 +261,24 @@ void ViewPureChecker::reportMutability( { // We do not warn for library functions because they cannot be payable anyway. // Also internal functions should be allowed to use `msg.value`. - if (m_currentFunction->isPublic() && !m_currentFunction->libraryFunction()) + if ((m_currentFunction->isConstructor() || m_currentFunction->isPublic()) && !m_currentFunction->libraryFunction()) { 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." + m_currentFunction->isConstructor() ? + "This modifier uses \"msg.value\" or \"callvalue()\" and thus the constructor has to be payable." + : "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." + m_currentFunction->isConstructor() ? + "\"msg.value\" and \"callvalue()\" can only be used in payable constructors. Make the constructor \"payable\" to avoid this error." + : "\"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." ); m_errors = true; } diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index cac28eac0..7094ccf83 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -208,6 +208,14 @@ vector, FunctionTypePointer>> const& ContractDefinition: }); } +uint64_t ContractDefinition::interfaceId() const +{ + uint64_t result{0}; + for (auto const& function: interfaceFunctionList(false)) + result ^= util::fromBigEndian(function.first.ref()); + return result; +} + TypePointer ContractDefinition::type() const { return TypeProvider::typeType(TypeProvider::contract(*this)); @@ -484,7 +492,7 @@ CallableDeclaration const* Scopable::functionOrModifierDefinition() const string Scopable::sourceUnitName() const { - return sourceUnit().annotation().path; + return *sourceUnit().annotation().path; } DeclarationAnnotation& Declaration::annotation() const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index cfa438ce5..4b1ecd2ca 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -152,10 +152,19 @@ std::vector ASTNode::filteredNodes(std::vector> co return ret; } +/** + * Abstract marker class that specifies that this AST node opens a scope. + */ +class ScopeOpener +{ +public: + virtual ~ScopeOpener() = default; +}; + /** * Source unit containing import directives and contract definitions. */ -class SourceUnit: public ASTNode +class SourceUnit: public ASTNode, public ScopeOpener { public: SourceUnit( @@ -455,7 +464,7 @@ protected: * document order. It first visits all struct declarations, then all variable declarations and * finally all function declarations. */ -class ContractDefinition: public Declaration, public StructurallyDocumented +class ContractDefinition: public Declaration, public StructurallyDocumented, public ScopeOpener { public: ContractDefinition( @@ -500,6 +509,8 @@ public: /// as intended for use by the ABI. std::map, FunctionTypePointer> interfaceFunctions(bool _includeInheritedFunctions = true) const; std::vector, FunctionTypePointer>> const& interfaceFunctionList(bool _includeInheritedFunctions = true) const; + /// @returns the EIP-165 compatible interface identifier. This will exclude inherited functions. + uint64_t interfaceId() const; /// @returns a list of all declarations in this contract std::vector declarations() const { return filteredNodes(m_subNodes); } @@ -593,7 +604,7 @@ private: ASTPointer m_typeName; }; -class StructDefinition: public Declaration +class StructDefinition: public Declaration, public ScopeOpener { public: StructDefinition( @@ -620,7 +631,7 @@ private: std::vector> m_members; }; -class EnumDefinition: public Declaration +class EnumDefinition: public Declaration, public ScopeOpener { public: EnumDefinition( @@ -765,7 +776,7 @@ protected: std::vector> m_overrides; }; -class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional +class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional, public ScopeOpener { public: FunctionDefinition( @@ -989,7 +1000,7 @@ private: /** * Definition of a function modifier. */ -class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional +class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional, public ScopeOpener { public: ModifierDefinition( @@ -1061,7 +1072,7 @@ private: /** * Definition of a (loggable) event. */ -class EventDefinition: public CallableDeclaration, public StructurallyDocumented +class EventDefinition: public CallableDeclaration, public StructurallyDocumented, public ScopeOpener { public: EventDefinition( @@ -1199,7 +1210,7 @@ private: /** * A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)" */ -class FunctionTypeName: public TypeName +class FunctionTypeName: public TypeName, public ScopeOpener { public: FunctionTypeName( @@ -1334,7 +1345,7 @@ private: /** * Brace-enclosed block containing zero or more statements. */ -class Block: public Statement, public Scopable +class Block: public Statement, public Scopable, public ScopeOpener { public: Block( @@ -1411,7 +1422,7 @@ private: * unsuccessful cases. * Names are only allowed for the unsuccessful cases. */ -class TryCatchClause: public ASTNode, public Scopable +class TryCatchClause: public ASTNode, public Scopable, public ScopeOpener { public: TryCatchClause( @@ -1526,7 +1537,7 @@ private: /** * For loop statement */ -class ForStatement: public BreakableStatement, public Scopable +class ForStatement: public BreakableStatement, public Scopable, public ScopeOpener { public: ForStatement( diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 2aac79837..2aa48d03e 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -47,6 +47,7 @@ namespace solidity::frontend class Type; using TypePointer = Type const*; +using namespace util; struct ASTAnnotation { @@ -88,9 +89,9 @@ struct StructurallyDocumentedAnnotation struct SourceUnitAnnotation: ASTAnnotation { /// The "absolute" (in the compiler sense) path of this source unit. - std::string path; + SetOnce path; /// The exported symbols (all global symbols). - std::map> exportedSymbols; + SetOnce>> exportedSymbols; /// Experimental features. std::set experimentalFeatures; }; @@ -108,10 +109,10 @@ struct ScopableAnnotation virtual ~ScopableAnnotation() = default; /// The scope this declaration resides in. Can be nullptr if it is the global scope. - /// Available only after name and type resolution step. + /// Filled by the Scoper. ASTNode const* scope = nullptr; /// Pointer to the contract this declaration resides in. Can be nullptr if the current scope - /// is not part of a contract. Available only after name and type resolution step. + /// is not part of a contract. Filled by the Scoper. ContractDefinition const* contract = nullptr; }; @@ -122,7 +123,7 @@ struct DeclarationAnnotation: ASTAnnotation, ScopableAnnotation struct ImportAnnotation: DeclarationAnnotation { /// The absolute path of the source unit to import. - std::string absolutePath; + SetOnce absolutePath; /// The actual source unit. SourceUnit const* sourceUnit = nullptr; }; @@ -130,7 +131,7 @@ struct ImportAnnotation: DeclarationAnnotation struct TypeDeclarationAnnotation: DeclarationAnnotation { /// The name of this type, prefixed by proper namespaces if globally accessible. - std::string canonicalName; + SetOnce canonicalName; }; struct StructDeclarationAnnotation: TypeDeclarationAnnotation @@ -149,7 +150,7 @@ struct StructDeclarationAnnotation: TypeDeclarationAnnotation struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation { /// List of functions and modifiers without a body. Can also contain functions from base classes. - std::vector unimplementedDeclarations; + std::optional> unimplementedDeclarations; /// List of all (direct and indirect) base contracts in order from derived to /// base, including the contract itself. std::vector linearizedBaseContracts; @@ -243,16 +244,16 @@ struct ExpressionAnnotation: ASTAnnotation /// Inferred type of the expression. TypePointer type = nullptr; /// Whether the expression is a constant variable - bool isConstant = false; + SetOnce isConstant; /// Whether the expression is pure, i.e. compile-time constant. - bool isPure = false; + SetOnce isPure; /// Whether it is an LValue (i.e. something that can be assigned to). - bool isLValue = false; + SetOnce isLValue; /// Whether the expression is used in a context where the LValue is actually required. bool willBeWrittenTo = false; /// Whether the expression is an lvalue that is only assigned. /// Would be false for --, ++, delete, +=, -=, .... - bool lValueOfOrdinaryAssignment = false; + SetOnce lValueOfOrdinaryAssignment; /// Types and - if given - names of arguments if the expr. is a function /// that is called, used for overload resolution diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index 3f082d975..80d37d399 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -38,6 +38,7 @@ namespace solidity::frontend { class ASTNode; +class ScopeOpener; class SourceUnit; class PragmaDirective; class ImportDirective; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 6d6d40775..34ae3c2b8 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -39,10 +39,33 @@ #include #include #include +#include using namespace std; using namespace solidity::langutil; +namespace +{ + +template typename C> +void addIfSet(std::vector>& _attributes, string const& _name, C const& _value) +{ + if constexpr (std::is_same_v, solidity::util::SetOnce>) + { + if (!_value.set()) + return; + } + else if constexpr (std::is_same_v, optional>) + { + if (!_value.has_value()) + return; + } + + _attributes.emplace_back(_name, *_value); +} + +} + namespace solidity::frontend { @@ -181,12 +204,14 @@ void ASTJsonConverter::appendExpressionAttributes( { std::vector> exprAttributes = { make_pair("typeDescriptions", typePointerToJson(_annotation.type)), - make_pair("isConstant", _annotation.isConstant), - make_pair("isPure", _annotation.isPure), - make_pair("isLValue", _annotation.isLValue), make_pair("lValueRequested", _annotation.willBeWrittenTo), make_pair("argumentTypes", typePointerToJson(_annotation.arguments)) }; + + addIfSet(exprAttributes, "isLValue", _annotation.isLValue); + addIfSet(exprAttributes, "isPure", _annotation.isPure); + addIfSet(exprAttributes, "isConstant", _annotation.isConstant); + _attributes += exprAttributes; } @@ -214,23 +239,27 @@ Json::Value ASTJsonConverter::toJson(ASTNode const& _node) bool ASTJsonConverter::visit(SourceUnit const& _node) { - Json::Value exportedSymbols = Json::objectValue; - for (auto const& sym: _node.annotation().exportedSymbols) + std::vector> attributes = { + make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue), + make_pair("nodes", toJson(_node.nodes())) + }; + + if (_node.annotation().exportedSymbols.set()) { - exportedSymbols[sym.first] = Json::arrayValue; - for (Declaration const* overload: sym.second) - exportedSymbols[sym.first].append(nodeId(*overload)); - } - setJsonNode( - _node, - "SourceUnit", + Json::Value exportedSymbols = Json::objectValue; + for (auto const& sym: *_node.annotation().exportedSymbols) { - 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())) + exportedSymbols[sym.first] = Json::arrayValue; + for (Declaration const* overload: sym.second) + exportedSymbols[sym.first].append(nodeId(*overload)); } - ); + + attributes.emplace_back("exportedSymbols", exportedSymbols); + }; + + addIfSet(attributes, "absolutePath", _node.annotation().path); + + setJsonNode(_node, "SourceUnit", std::move(attributes)); return false; } @@ -249,10 +278,12 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) { std::vector> attributes = { make_pair("file", _node.path()), - make_pair("absolutePath", _node.annotation().absolutePath), make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)), make_pair("scope", idOrNull(_node.scope())) }; + + addIfSet(attributes, "absolutePath", _node.annotation().absolutePath); + attributes.emplace_back("unitAlias", _node.name()); Json::Value symbolAliases(Json::arrayValue); for (auto const& symbolAlias: _node.symbolAliases()) @@ -270,18 +301,23 @@ bool ASTJsonConverter::visit(ImportDirective const& _node) bool ASTJsonConverter::visit(ContractDefinition const& _node) { - setJsonNode(_node, "ContractDefinition", { + std::vector> attributes = { make_pair("name", _node.name()), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("contractKind", contractKind(_node.contractKind())), make_pair("abstract", _node.abstract()), - make_pair("fullyImplemented", _node.annotation().unimplementedDeclarations.empty()), - make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)), make_pair("baseContracts", toJson(_node.baseContracts())), make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies, true)), make_pair("nodes", toJson(_node.subNodes())), make_pair("scope", idOrNull(_node.scope())) - }); + }; + + if (_node.annotation().unimplementedDeclarations.has_value()) + attributes.emplace_back("fullyImplemented", _node.annotation().unimplementedDeclarations->empty()); + if (!_node.annotation().linearizedBaseContracts.empty()) + attributes.emplace_back("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)); + + setJsonNode(_node, "ContractDefinition", std::move(attributes)); return false; } @@ -305,23 +341,31 @@ bool ASTJsonConverter::visit(UsingForDirective const& _node) bool ASTJsonConverter::visit(StructDefinition const& _node) { - setJsonNode(_node, "StructDefinition", { + std::vector> attributes = { make_pair("name", _node.name()), make_pair("visibility", Declaration::visibilityToString(_node.visibility())), - make_pair("canonicalName", _node.annotation().canonicalName), make_pair("members", toJson(_node.members())), make_pair("scope", idOrNull(_node.scope())) - }); + }; + + addIfSet(attributes,"canonicalName", _node.annotation().canonicalName); + + setJsonNode(_node, "StructDefinition", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(EnumDefinition const& _node) { - setJsonNode(_node, "EnumDefinition", { + std::vector> attributes = { make_pair("name", _node.name()), - make_pair("canonicalName", _node.annotation().canonicalName), make_pair("members", toJson(_node.members())) - }); + }; + + addIfSet(attributes,"canonicalName", _node.annotation().canonicalName); + + setJsonNode(_node, "EnumDefinition", std::move(attributes)); + return false; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 52b206737..a874bab9c 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -44,6 +44,7 @@ #include #include +#include #include using namespace std; @@ -54,57 +55,6 @@ using namespace solidity::frontend; namespace { -struct TypeComp -{ - bool operator()(Type const* lhs, Type const* rhs) const - { - solAssert(lhs && rhs, ""); - return lhs->richIdentifier() < rhs->richIdentifier(); - } -}; -using TypeSet = std::set; - -void oversizedSubtypesInner( - Type const& _type, - bool _includeType, - set& _structsSeen, - TypeSet& _oversizedSubtypes -) -{ - switch (_type.category()) - { - case Type::Category::Array: - { - auto const& t = dynamic_cast(_type); - if (_includeType && t.storageSizeUpperBound() >= bigint(1) << 64) - _oversizedSubtypes.insert(&t); - oversizedSubtypesInner(*t.baseType(), t.isDynamicallySized(), _structsSeen, _oversizedSubtypes); - break; - } - case Type::Category::Struct: - { - auto const& t = dynamic_cast(_type); - if (_structsSeen.count(&t.structDefinition())) - return; - if (_includeType && t.storageSizeUpperBound() >= bigint(1) << 64) - _oversizedSubtypes.insert(&t); - _structsSeen.insert(&t.structDefinition()); - for (auto const& m: t.members(nullptr)) - oversizedSubtypesInner(*m.type, false, _structsSeen, _oversizedSubtypes); - _structsSeen.erase(&t.structDefinition()); - break; - } - case Type::Category::Mapping: - { - auto const* valueType = dynamic_cast(_type).valueType(); - oversizedSubtypesInner(*valueType, true, _structsSeen, _oversizedSubtypes); - break; - } - default: - break; - } -} - /// Check whether (_base ** _exp) fits into 4096 bits. bool fitsPrecisionExp(bigint const& _base, bigint const& _exp) { @@ -201,16 +151,6 @@ util::Result transformParametersToExternal(TypePointers const& _pa } -vector solidity::frontend::oversizedSubtypes(frontend::Type const& _type) -{ - set structsSeen; - TypeSet oversized; - oversizedSubtypesInner(_type, false, structsSeen, oversized); - vector res; - copy(oversized.cbegin(), oversized.cend(), back_inserter(res)); - return res; -} - void Type::clearCache() const { m_members.clear(); @@ -404,10 +344,16 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c return encodingType; TypePointer baseType = encodingType; while (auto const* arrayType = dynamic_cast(baseType)) + { baseType = arrayType->baseType(); - if (dynamic_cast(baseType)) - if (!_encoderV2) + + auto const* baseArrayType = dynamic_cast(baseType); + if (!_encoderV2 && baseArrayType && baseArrayType->isDynamicallySized()) return nullptr; + } + if (!_encoderV2 && dynamic_cast(baseType)) + return nullptr; + return encodingType; } @@ -1405,12 +1351,25 @@ StringLiteralType::StringLiteralType(string _value): BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (auto fixedBytes = dynamic_cast(&_convertTo)) - return static_cast(fixedBytes->numBytes()) >= m_value.size(); + { + if (static_cast(fixedBytes->numBytes()) < m_value.size()) + return BoolResult::err("Literal is larger than the type."); + return true; + } else if (auto arrayType = dynamic_cast(&_convertTo)) + { + size_t invalidSequence; + if (arrayType->isString() && !util::validateUTF8(value(), invalidSequence)) + return BoolResult::err( + "Contains invalid UTF-8 sequence at position " + + util::toString(invalidSequence) + + "." + ); return + arrayType->location() != DataLocation::CallData && arrayType->isByteArray() && - !(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer()) && - !(arrayType->isString() && !util::validateUTF8(value())); + !(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer()); + } else return false; } @@ -1431,12 +1390,19 @@ bool StringLiteralType::operator==(Type const& _other) const std::string StringLiteralType::toString(bool) const { - size_t invalidSequence; + auto isPrintableASCII = [](string const& s) + { + for (auto c: s) + { + if (static_cast(c) <= 0x1f || static_cast(c) >= 0x7f) + return false; + } + return true; + }; - if (!util::validateUTF8(m_value, invalidSequence)) - return "literal_string (contains invalid UTF-8 sequence at position " + util::toString(invalidSequence) + ")"; - - return "literal_string \"" + m_value + "\""; + return isPrintableASCII(m_value) ? + ("literal_string \"" + m_value + "\"") : + ("literal_string hex\"" + util::toHex(util::asBytes(m_value)) + "\""); } TypePointer StringLiteralType::mobileType() const @@ -1569,12 +1535,15 @@ BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const return true; if (_convertTo.category() == Category::Contract) { - auto const& bases = contractDefinition().annotation().linearizedBaseContracts; - if (m_super && bases.size() <= 1) + auto const& targetContractType = dynamic_cast(_convertTo); + if (targetContractType.isSuper()) return false; + + auto const& bases = contractDefinition().annotation().linearizedBaseContracts; return find( - m_super ? ++bases.begin() : bases.begin(), bases.end(), - &dynamic_cast(_convertTo).contractDefinition() + bases.begin(), + bases.end(), + &targetContractType.contractDefinition() ) != bases.end(); } return false; @@ -1608,6 +1577,21 @@ TypeResult ContractType::unaryOperatorResult(Token _operator) const return nullptr; } +vector CompositeType::fullDecomposition() const +{ + vector res = {this}; + unordered_set seen = {richIdentifier()}; + for (size_t k = 0; k < res.size(); ++k) + if (auto composite = dynamic_cast(res[k])) + for (Type const* next: composite->decomposition()) + if (seen.count(next->richIdentifier()) == 0) + { + seen.insert(next->richIdentifier()); + res.push_back(next); + } + return res; +} + Type const* ReferenceType::withLocation(DataLocation _location, bool _isPointer) const { return TypeProvider::withLocation(this, _location, _isPointer); @@ -2150,7 +2134,7 @@ string ContractType::toString(bool) const string ContractType::canonicalName() const { - return m_contract.annotation().canonicalName; + return *m_contract.annotation().canonicalName; } MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const @@ -2401,7 +2385,7 @@ bool StructType::containsNestedMapping() const string StructType::toString(bool _short) const { - string ret = "struct " + m_struct.annotation().canonicalName; + string ret = "struct " + *m_struct.annotation().canonicalName; if (!_short) ret += " " + stringForReferencePart(); return ret; @@ -2580,7 +2564,7 @@ string StructType::signatureInExternalFunction(bool _structsByName) const string StructType::canonicalName() const { - return m_struct.annotation().canonicalName; + return *m_struct.annotation().canonicalName; } FunctionTypePointer StructType::constructorType() const @@ -2645,6 +2629,13 @@ vector> StructType::makeStackItems() const solAssert(false, ""); } +vector StructType::decomposition() const +{ + vector res; + for (MemberList::Member const& member: members(nullptr)) + res.push_back(member.type); + return res; +} TypePointer EnumType::encodingType() const { @@ -2680,12 +2671,12 @@ unsigned EnumType::storageBytes() const string EnumType::toString(bool) const { - return string("enum ") + m_enum.annotation().canonicalName; + return string("enum ") + *m_enum.annotation().canonicalName; } string EnumType::canonicalName() const { - return m_enum.annotation().canonicalName; + return *m_enum.annotation().canonicalName; } size_t EnumType::numberOfMembers() const @@ -3007,7 +2998,7 @@ TypePointers FunctionType::returnParameterTypesWithoutDynamicTypes() const m_kind == Kind::BareStaticCall ) for (auto& param: returnParameterTypes) - if (param->isDynamicallySized() && !param->dataStoredIn(DataLocation::Storage)) + if (param->isDynamicallyEncoded() && !param->dataStoredIn(DataLocation::Storage)) param = TypeProvider::inaccessibleDynamic(); return returnParameterTypes; @@ -3158,7 +3149,7 @@ string FunctionType::toString(bool _short) const auto const* functionDefinition = dynamic_cast(m_declaration); solAssert(functionDefinition, ""); if (auto const* contract = dynamic_cast(functionDefinition->scope())) - name += contract->annotation().canonicalName + "."; + name += *contract->annotation().canonicalName + "."; name += functionDefinition->name(); } name += '('; @@ -3482,12 +3473,12 @@ bool FunctionType::canTakeArguments( size_t matchedNames = 0; - for (auto const& argName: _arguments.names) - for (size_t i = 0; i < paramNames.size(); i++) - if (*argName == paramNames[i]) + for (size_t a = 0; a < _arguments.names.size(); a++) + for (size_t p = 0; p < paramNames.size(); p++) + if (*_arguments.names[a] == paramNames[p]) { matchedNames++; - if (!_arguments.types[i]->isImplicitlyConvertibleTo(*paramTypes[i])) + if (!_arguments.types[a]->isImplicitlyConvertibleTo(*paramTypes[p])) return false; } @@ -3949,7 +3940,7 @@ bool ModuleType::operator==(Type const& _other) const MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const { MemberList::MemberMap symbols; - for (auto const& symbolName: m_sourceUnit.annotation().exportedSymbols) + for (auto const& symbolName: *m_sourceUnit.annotation().exportedSymbols) for (Declaration const* symbol: symbolName.second) symbols.emplace_back(symbolName.first, symbol->type(), symbol); return symbols; @@ -3957,7 +3948,7 @@ MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const string ModuleType::toString(bool) const { - return string("module \"") + m_sourceUnit.annotation().path + string("\""); + return string("module \"") + *m_sourceUnit.annotation().path + string("\""); } string MagicType::richIdentifier() const diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 9b32475ca..f70398a9f 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -60,8 +60,6 @@ using BoolResult = util::Result; namespace solidity::frontend { -std::vector oversizedSubtypes(frontend::Type const& _type); - inline rational makeRational(bigint const& _numerator, bigint const& _denominator) { solAssert(_denominator != 0, "division by zero"); @@ -694,11 +692,37 @@ public: TypeResult interfaceType(bool) const override { return this; } }; +/** + * Base class for types which can be thought of as several elements of other types put together. + * For example a struct is composed of its members, an array is composed of multiple copies of its + * base element and a mapping is composed of its value type elements (note that keys are not + * stored anywhere). + */ +class CompositeType: public Type +{ +protected: + CompositeType() = default; + +public: + /// @returns a list containing the type itself, elements of its decomposition, + /// elements of decomposition of these elements and so on, up to non-composite types. + /// Each type is included only once. + std::vector fullDecomposition() const; + +protected: + /// @returns a list of types that together make up the data part of this type. + /// Contains all types that will have to be implicitly stored, whenever an object of this type is stored. + /// In particular, it returns the base type for arrays and array slices, the member types for structs, + /// the component types for tuples and the value type for mappings + /// (note that the key type of a mapping is *not* part of the list). + virtual std::vector decomposition() const = 0; +}; + /** * Base class used by types which are not value types and can be stored either in storage, memory * or calldata. This is currently used by arrays and structs. */ -class ReferenceType: public Type +class ReferenceType: public CompositeType { protected: explicit ReferenceType(DataLocation _location): m_location(_location) {} @@ -829,6 +853,8 @@ public: protected: std::vector> makeStackItems() const override; + std::vector decomposition() const override { return {m_baseType}; } + private: /// String is interpreted as a subtype of Bytes. enum class ArrayKind { Ordinary, Bytes, String }; @@ -869,6 +895,8 @@ public: protected: std::vector> makeStackItems() const override; + std::vector decomposition() const override { return {m_arrayType.baseType()}; } + private: ArrayType const& m_arrayType; }; @@ -994,6 +1022,8 @@ public: protected: std::vector> makeStackItems() const override; + std::vector decomposition() const override; + private: StructDefinition const& m_struct; // Caches for interfaceType(bool) @@ -1044,7 +1074,7 @@ private: * Type that can hold a finite sequence of values of different types. * In some cases, the components are empty pointers (when used as placeholders). */ -class TupleType: public Type +class TupleType: public CompositeType { public: explicit TupleType(std::vector _types = {}): m_components(std::move(_types)) {} @@ -1067,6 +1097,16 @@ public: protected: std::vector> makeStackItems() const override; + std::vector decomposition() const override + { + // Currently calling TupleType::decomposition() is not expected, because we cannot declare a variable of a tuple type. + // If that changes, before removing the solAssert, make sure the function does the right thing and is used properly. + // Note that different tuple members can have different data locations, so using decomposition() to check + // the tuple validity for a data location might require special care. + solUnimplemented("Tuple decomposition is not expected."); + return m_components; + } + private: std::vector const m_components; }; @@ -1349,7 +1389,7 @@ private: * The type of a mapping, there is one distinct type per key/value type pair. * Mappings always occupy their own storage slot, but do not actually use it. */ -class MappingType: public Type +class MappingType: public CompositeType { public: MappingType(Type const* _keyType, Type const* _valueType): @@ -1373,6 +1413,9 @@ public: Type const* keyType() const { return m_keyType; } Type const* valueType() const { return m_valueType; } +protected: + std::vector decomposition() const override { return {m_valueType}; } + private: TypePointer m_keyType; TypePointer m_valueType; diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index a64a34009..0b6385943 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -51,8 +51,8 @@ void Compiler::compileContract( m_context.optimise(m_optimiserSettings); - solAssert(m_context.requestedYulFunctionsRan(), "requestedYulFunctions() was not called."); - solAssert(m_runtimeContext.requestedYulFunctionsRan(), "requestedYulFunctions() was not called."); + solAssert(m_context.appendYulUtilityFunctionsRan(), "appendYulUtilityFunctions() was not called."); + solAssert(m_runtimeContext.appendYulUtilityFunctionsRan(), "appendYulUtilityFunctions() was not called."); } std::shared_ptr Compiler::runtimeAssemblyPtr() const diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index 11d5c2abd..4dbbeb099 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -74,6 +74,9 @@ public: /// @returns Assembly items of the runtime compiler context evmasm::AssemblyItems const& runtimeAssemblyItems() const { return m_context.assembly().sub(m_runtimeSub).items(); } + std::string generatedYulUtilityCode() const { return m_context.generatedYulUtilityCode(); } + std::string runtimeGeneratedYulUtilityCode() const { return m_runtimeContext.generatedYulUtilityCode(); } + /// @returns the entry label of the given function. Might return an AssemblyItem of type /// UndefinedItem if it does not exist yet. evmasm::AssemblyItem functionEntryLabel(FunctionDefinition const& _function) const; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 9fde94e8a..ff52e626c 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include @@ -51,9 +53,6 @@ // Change to "define" to output all intermediate code #undef SOL_OUTPUT_ASM -#ifdef SOL_OUTPUT_ASM -#include -#endif using namespace std; @@ -191,14 +190,24 @@ void CompilerContext::appendMissingLowLevelFunctions() } } -pair> CompilerContext::requestedYulFunctions() +void CompilerContext::appendYulUtilityFunctions(OptimiserSettings const& _optimiserSettings) { - solAssert(!m_requestedYulFunctionsRan, "requestedYulFunctions called more than once."); - m_requestedYulFunctionsRan = true; + solAssert(!m_appendYulUtilityFunctionsRan, "requestedYulFunctions called more than once."); + m_appendYulUtilityFunctionsRan = true; - set empty; - swap(empty, m_externallyUsedYulFunctions); - return {m_yulFunctionCollector.requestedFunctions(), std::move(empty)}; + string code = m_yulFunctionCollector.requestedFunctions(); + if (!code.empty()) + { + appendInlineAssembly( + yul::reindent("{\n" + move(code) + "\n}"), + {}, + m_externallyUsedYulFunctions, + true, + _optimiserSettings, + yulUtilityFileName() + ); + solAssert(!m_generatedYulUtilityCode.empty(), ""); + } } void CompilerContext::addVariable( @@ -369,7 +378,8 @@ void CompilerContext::appendInlineAssembly( vector const& _localVariables, set const& _externallyUsedFunctions, bool _system, - OptimiserSettings const& _optimiserSettings + OptimiserSettings const& _optimiserSettings, + string _sourceName ) { unsigned startStackHeight = stackHeight(); @@ -420,7 +430,7 @@ void CompilerContext::appendInlineAssembly( ErrorList errors; ErrorReporter errorReporter(errors); - auto scanner = make_shared(langutil::CharStream(_assembly, "--CODEGEN--")); + auto scanner = make_shared(langutil::CharStream(_assembly, _sourceName)); yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion); optional locationOverride; if (!_system) @@ -469,6 +479,17 @@ void CompilerContext::appendInlineAssembly( optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers); + if (_system) + { + // Store as generated sources, but first re-parse to update the source references. + solAssert(m_generatedYulUtilityCode.empty(), ""); + m_generatedYulUtilityCode = yul::AsmPrinter(dialect)(*obj.code); + string code = yul::AsmPrinter{dialect}(*obj.code); + scanner = make_shared(langutil::CharStream(m_generatedYulUtilityCode, _sourceName)); + obj.code = yul::Parser(errorReporter, dialect).parse(scanner, false); + *obj.analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(dialect, obj); + } + analysisInfo = std::move(*obj.analysisInfo); parserResult = std::move(obj.code); @@ -477,6 +498,12 @@ void CompilerContext::appendInlineAssembly( cout << yul::AsmPrinter(&dialect)(*parserResult) << endl; #endif } + else if (_system) + { + // Store as generated source. + solAssert(m_generatedYulUtilityCode.empty(), ""); + m_generatedYulUtilityCode = _assembly; + } if (!errorReporter.errors().empty()) reportError("Failed to analyze inline assembly block."); diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index f82c705d8..72ed4fe6f 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -163,12 +163,14 @@ public: void appendMissingLowLevelFunctions(); ABIFunctions& abiFunctions() { return m_abiFunctions; } YulUtilFunctions& utilFunctions() { return m_yulUtilFunctions; } - /// @returns concatenation of all generated functions and a set of the - /// externally used functions. - /// 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; } + + /// Appends concatenation of all generated Yul functions to the bytecode + /// and stores the Yul source code to be returned by @a generatedYulUtilityCode. + /// Should be called exactly once on each context. + void appendYulUtilityFunctions(OptimiserSettings const& _optimiserSettings); + bool appendYulUtilityFunctionsRan() const { return m_appendYulUtilityFunctionsRan; } + std::string const& generatedYulUtilityCode() const { return m_generatedYulUtilityCode; } + static std::string yulUtilityFileName() { return "#utility.yul"; } /// Returns the distance of the given local variable from the bottom of the stack (of the current function). unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; @@ -246,17 +248,21 @@ public: CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; } CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; } - /// Appends inline assembly (strict mode). - /// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly. + /// Appends inline assembly (strict-EVM dialect for the current version). + /// @param _assembly the assembly text, should be a block. /// @param _localVariables assigns stack positions to variables with the last one being the stack top /// @param _externallyUsedFunctions a set of function names that are not to be renamed or removed. - /// @param _system if true, this is a "system-level" assembly where all functions use named labels. + /// @param _system if true, this is a "system-level" assembly where all functions use named labels + /// and the code is marked to be exported as "compiler-generated assembly utility file". + /// @param _optimiserSettings settings for the Yul optimiser, which is run in this function already. + /// @param _sourceName the name of the assembly file to be used for source locations void appendInlineAssembly( std::string const& _assembly, std::vector const& _localVariables = std::vector(), std::set const& _externallyUsedFunctions = std::set(), bool _system = false, - OptimiserSettings const& _optimiserSettings = OptimiserSettings::none() + OptimiserSettings const& _optimiserSettings = OptimiserSettings::none(), + std::string _sourceName = "--CODEGEN--" ); /// If m_revertStrings is debug, @returns inline assembly code that @@ -385,14 +391,17 @@ private: MultiUseYulFunctionCollector m_yulFunctionCollector; /// Set of externally used yul functions. std::set m_externallyUsedYulFunctions; + /// Generated Yul code used as utility. Source references from the bytecode can point here. + /// Produced from @a m_yulFunctionCollector. + std::string m_generatedYulUtilityCode; /// Container for ABI functions to be generated. ABIFunctions m_abiFunctions; /// Container for Yul Util functions to be generated. 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; + /// Flag to check that appendYulUtilityFunctions() was called exactly once + bool m_appendYulUtilityFunctionsRan = false; }; } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index cbad912a8..651152a2c 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -1272,15 +1272,7 @@ void ContractCompiler::appendMissingFunctions() solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?"); } m_context.appendMissingLowLevelFunctions(); - auto [yulFunctions, externallyUsedYulFunctions] = m_context.requestedYulFunctions(); - if (!yulFunctions.empty()) - m_context.appendInlineAssembly( - "{" + move(yulFunctions) + "}", - {}, - externallyUsedYulFunctions, - true, - m_optimiserSettings - ); + m_context.appendYulUtilityFunctions(m_optimiserSettings); } void ContractCompiler::appendModifierOrFunctionCode() diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index d4badc197..64c86fc2d 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -143,6 +143,7 @@ private: /// Pointer to the runtime compiler in case this is a creation compiler. ContractCompiler* m_runtimeCompiler = nullptr; CompilerContext& m_context; + /// Tag to jump to for a "break" statement and the stack height after freeing the local loop variables. std::vector> m_breakTags; /// Tag to jump to for a "continue" statement and the stack height after freeing the local loop variables. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index d4f70691f..f096583db 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -779,7 +779,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) solAssert(function.parameterTypes().size() == 1, ""); if (m_context.revertStrings() == RevertStrings::Strip) { - if (!arguments.front()->annotation().isPure) + if (!*arguments.front()->annotation().isPure) { arguments.front()->accept(*this); utils().popStackElement(*arguments.front()->annotation().type); @@ -1078,7 +1078,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) solAssert(function.kind() == FunctionType::Kind::Require, ""); if (m_context.revertStrings() == RevertStrings::Strip) { - if (!arguments.at(1)->annotation().isPure) + if (!*arguments.at(1)->annotation().isPure) { arguments.at(1)->accept(*this); utils().popStackElement(*arguments.at(1)->annotation().type); @@ -1598,10 +1598,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); - uint64_t result{0}; - for (auto const& function: contract.interfaceFunctionList(false)) - result ^= fromBigEndian(function.first.ref()); - m_context << (u256{result} << (256 - 32)); + m_context << (u256{contract.interfaceId()} << (256 - 32)); } else if (member == "min" || member == "max") { diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index b2f3ad8dd..4ac32a1fa 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -118,10 +118,10 @@ string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _mess if (!_messageType) return Whiskers(R"( function (condition) { - if iszero(condition) { } + if iszero(condition) { } } )") - ("invalidOrRevert", _assert ? "invalid()" : "revert(0, 0)") + ("error", _assert ? panicFunction() + "()" : "revert(0, 0)") ("functionName", functionName) .render(); @@ -457,7 +457,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) string functionName = "checked_add_" + _type.identifier(); // TODO: Consider to add a special case for unsigned 256-bit integers // and use the following instead: - // sum := add(x, y) if lt(sum, x) { revert(0, 0) } + // sum := add(x, y) if lt(sum, x) { () } return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( @@ -466,12 +466,12 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) y := (y) // overflow, if x >= 0 and y > (maxValue - x) - if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { revert(0, 0) } + if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { () } // underflow, if x < 0 and y < (minValue - x) - if and(slt(x, 0), slt(y, sub(, x))) { revert(0, 0) } + if and(slt(x, 0), slt(y, sub(, x))) { () } // overflow, if x > (maxValue - y) - if gt(x, sub(, y)) { revert(0, 0) } + if gt(x, sub(, y)) { () } sum := add(x, y) } @@ -481,6 +481,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("panic", panicFunction()) .render(); }); } @@ -497,16 +498,16 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) 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) } + if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { () } // underflow, if x > 0, y < 0 and y < (minValue / x) - if and(and(sgt(x, 0), slt(y, 0)), slt(y, sdiv(, x))) { revert(0, 0) } + if and(and(sgt(x, 0), slt(y, 0)), slt(y, sdiv(, x))) { () } // underflow, if x < 0, y > 0 and x < (minValue / y) - if and(and(slt(x, 0), sgt(y, 0)), slt(x, sdiv(, y))) { revert(0, 0) } + if and(and(slt(x, 0), sgt(y, 0)), slt(x, sdiv(, y))) { () } // overflow, if x < 0, y < 0 and x < (maxValue / y) - if and(and(slt(x, 0), slt(y, 0)), slt(x, sdiv(, y))) { revert(0, 0) } + if and(and(slt(x, 0), slt(y, 0)), slt(x, sdiv(, y))) { () } // overflow, if x != 0 and y > (maxValue / x) - if and(iszero(iszero(x)), gt(y, div(, x))) { revert(0, 0) } + if and(iszero(iszero(x)), gt(y, div(, x))) { () } product := mul(x, y) } @@ -516,6 +517,7 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("panic", panicFunction()) .render(); }); } @@ -529,13 +531,13 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) function (x, y) -> r { x := (x) y := (y) - if iszero(y) { revert(0, 0) } + if iszero(y) { () } // overflow for minVal / -1 if and( eq(x, ), eq(y, sub(0, 1)) - ) { revert(0, 0) } + ) { () } r := sdiv(x, y) } @@ -544,6 +546,7 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("minVal", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("panic", panicFunction()) .render(); }); } @@ -557,13 +560,14 @@ string YulUtilFunctions::checkedIntModFunction(IntegerType const& _type) function (x, y) -> r { x := (x) y := (y) - if iszero(y) { revert(0, 0) } + if iszero(y) { () } r := smod(x, y) } )") ("functionName", functionName) ("signed", _type.isSigned()) ("cleanupFunction", cleanupFunction(_type)) + ("panic", panicFunction()) .render(); }); } @@ -579,11 +583,11 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) y := (y) // underflow, if y >= 0 and x < (minValue + y) - if and(iszero(slt(y, 0)), slt(x, add(, y))) { revert(0, 0) } + if and(iszero(slt(y, 0)), slt(x, add(, y))) { () } // overflow, if y < 0 and x > (maxValue + y) - if and(slt(y, 0), sgt(x, add(, y))) { revert(0, 0) } + if and(slt(y, 0), sgt(x, add(, y))) { () } - if lt(x, y) { revert(0, 0) } + if lt(x, y) { () } diff := sub(x, y) } @@ -593,6 +597,7 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("panic", panicFunction()) .render(); }); } @@ -632,6 +637,16 @@ string YulUtilFunctions::overflowCheckedIntExpFunction( string YulUtilFunctions::overflowCheckedUnsignedExpFunction() { + // Checks for the "small number specialization" below. + using namespace boost::multiprecision; + solAssert(pow(bigint(10), 77) < pow(bigint(2), 256), ""); + solAssert(pow(bigint(11), 77) >= pow(bigint(2), 256), ""); + solAssert(pow(bigint(10), 78) >= pow(bigint(2), 256), ""); + + solAssert(pow(bigint(306), 31) < pow(bigint(2), 256), ""); + solAssert(pow(bigint(307), 31) >= pow(bigint(2), 256), ""); + solAssert(pow(bigint(306), 32) >= pow(bigint(2), 256), ""); + string functionName = "checked_exp_unsigned"; return m_functionCollector.createFunction(functionName, [&]() { return @@ -644,25 +659,36 @@ string YulUtilFunctions::overflowCheckedUnsignedExpFunction() if iszero(exponent) { power := 1 leave } if iszero(base) { power := 0 leave } - power := 1 - - for { } gt(exponent, 1) {} + // Specializations for small bases + switch base + // 0 is handled above + case 1 { power := 1 leave } + case 2 { - // overflow check for base * base - if gt(base, div(max, base)) { revert(0, 0) } - if and(exponent, 1) - { - // no check needed here because base >= power - power := mul(power, base) - } - base := mul(base, base) - exponent := (exponent) + if gt(exponent, 255) { () } + power := exp(2, exponent) + if gt(power, max) { () } + leave } - if gt(power, div(max, base)) { revert(0, 0) } + if or( + and(lt(base, 11), lt(exponent, 78)), + and(lt(base, 307), lt(exponent, 32)) + ) + { + power := exp(base, exponent) + if gt(power, max) { () } + leave + } + + power, base := (1, base, exponent, max) + + if gt(power, div(max, base)) { () } power := mul(power, base) } )") ("functionName", functionName) + ("panic", panicFunction()) + ("expLoop", overflowCheckedExpLoopFunction()) ("shr_1", shiftRightFunction(1)) .render(); }); @@ -692,8 +718,8 @@ string YulUtilFunctions::overflowCheckedSignedExpFunction() // overflow check for base * base switch sgt(base, 0) - case 1 { if gt(base, div(max, base)) { revert(0, 0) } } - case 0 { if slt(base, sdiv(max, base)) { revert(0, 0) } } + case 1 { if gt(base, div(max, base)) { () } } + case 0 { if slt(base, sdiv(max, base)) { () } } if and(exponent, 1) { power := base @@ -703,28 +729,56 @@ string YulUtilFunctions::overflowCheckedSignedExpFunction() // Below this point, base is always positive. + power, base := (power, base, exponent, max) + + if and(sgt(power, 0), gt(power, div(max, base))) { () } + if and(slt(power, 0), slt(power, sdiv(min, base))) { () } + power := mul(power, base) + } + )") + ("functionName", functionName) + ("panic", panicFunction()) + ("expLoop", overflowCheckedExpLoopFunction()) + ("shr_1", shiftRightFunction(1)) + .render(); + }); +} + +string YulUtilFunctions::overflowCheckedExpLoopFunction() +{ + // We use this loop for both signed and unsigned exponentiation + // because we pull out the first iteration in the signed case which + // results in the base always being positive. + + // This function does not include the final multiplication. + + string functionName = "checked_exp_helper"; + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (_power, _base, exponent, max) -> power, base { + power := _power + base := _base for { } gt(exponent, 1) {} { // overflow check for base * base - if gt(base, div(max, base)) { revert(0, 0) } + if gt(base, div(max, base)) { () } if and(exponent, 1) { // No checks for power := mul(power, base) needed, because the check // for base * base above is sufficient, since: // |power| <= base (proof by induction) and thus: - // |power * base| <= base * base <= max <= |min| + // |power * base| <= base * base <= max <= |min| (for signed) + // (this is equally true for signed and unsigned exp) power := mul(power, base) } base := mul(base, base) exponent := (exponent) } - - if and(sgt(power, 0), gt(power, div(max, base))) { revert(0, 0) } - if and(slt(power, 0), slt(power, sdiv(min, base))) { revert(0, 0) } - power := mul(power, base) } )") ("functionName", functionName) + ("panic", panicFunction()) ("shr_1", shiftRightFunction(1)) .render(); }); @@ -804,7 +858,7 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type) return Whiskers(R"( function (array, newLen) { if gt(newLen, ) { - invalid() + () } let oldLen := (array) @@ -823,6 +877,7 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type) } })") ("functionName", functionName) + ("panic", panicFunction()) ("fetchLength", arrayLengthFunction(_type)) ("convertToSize", arrayConvertLengthToSize(_type)) ("dataPosition", arrayDataAreaFunction(_type)) @@ -845,13 +900,14 @@ string YulUtilFunctions::storageArrayPopFunction(ArrayType const& _type) return Whiskers(R"( function (array) { let oldLen := (array) - if iszero(oldLen) { invalid() } + if iszero(oldLen) { () } let newLen := sub(oldLen, 1) let slot, offset := (array, newLen) (slot, offset) sstore(array, newLen) })") ("functionName", functionName) + ("panic", panicFunction()) ("fetchLength", arrayLengthFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type)) ("setToZero", storageSetToZeroFunction(*_type.baseType())) @@ -871,7 +927,7 @@ string YulUtilFunctions::storageByteArrayPopFunction(ArrayType const& _type) function (array) { let data := sload(array) let oldLen := (data) - if iszero(oldLen) { invalid() } + if iszero(oldLen) { () } switch eq(oldLen, 32) case 1 { @@ -900,6 +956,7 @@ string YulUtilFunctions::storageByteArrayPopFunction(ArrayType const& _type) sstore(array, data) })") ("functionName", functionName) + ("panic", panicFunction()) ("extractByteArrayLength", extractByteArrayLengthFunction()) ("dataAreaFunction", arrayDataAreaFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type)) @@ -922,7 +979,7 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type) let data := sload(array) let oldLen := (data) - if iszero(lt(oldLen, )) { invalid() } + if iszero(lt(oldLen, )) { () } switch gt(oldLen, 31) case 0 { @@ -953,13 +1010,14 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type) } let oldLen := sload(array) - if iszero(lt(oldLen, )) { invalid() } + if iszero(lt(oldLen, )) { () } sstore(array, add(oldLen, 1)) let slot, offset := (array, oldLen) (slot, offset, value) })") ("functionName", functionName) + ("panic", panicFunction()) ("extractByteArrayLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "") ("dataAreaFunction", arrayDataAreaFunction(_type)) ("isByteArray", _type.isByteArray()) @@ -986,12 +1044,13 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type) return Whiskers(R"( function (array) -> slot, offset { let oldLen := (array) - if iszero(lt(oldLen, )) { invalid() } + if iszero(lt(oldLen, )) { () } sstore(array, add(oldLen, 1)) slot, offset := (array, oldLen) (slot, offset, ()) })") ("functionName", functionName) + ("panic", panicFunction()) ("fetchLength", arrayLengthFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type)) ("storeValue", updateStorageValueFunction(*_type.baseType(), *_type.baseType())) @@ -1126,7 +1185,7 @@ string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type) Whiskers w(R"( function (length) -> size { // Make sure we can allocate memory without overflow - if gt(length, 0xffffffffffffffff) { revert(0, 0) } + if gt(length, 0xffffffffffffffff) { () } // round up size := and(add(length, 0x1f), not(0x1f)) @@ -1140,6 +1199,7 @@ string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type) } )"); w("functionName", functionName); + w("panic", panicFunction()); w("byteArray", _type.isByteArray()); w("dynamic", _type.isDynamicallySized()); return w.render(); @@ -1184,7 +1244,7 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type) return Whiskers(R"( function (array, index) -> slot, offset { let arrayLength := (array) - if iszero(lt(index, arrayLength)) { invalid() } + if iszero(lt(index, arrayLength)) { () } @@ -1198,10 +1258,9 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type) slot := array } - let itemsPerSlot := div(0x20, ) let dataArea := (array) - slot := add(dataArea, div(index, itemsPerSlot)) - offset := mod(index, itemsPerSlot) + slot := add(dataArea, div(index, )) + offset := mul(mod(index, ), ) let dataArea := (array) @@ -1211,12 +1270,14 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type) } )") ("functionName", functionName) + ("panic", panicFunction()) ("arrayLen", arrayLengthFunction(_type)) ("dataAreaFunc", arrayDataAreaFunction(_type)) ("multipleItemsPerSlot", _type.baseType()->storageBytes() <= 16) ("isBytesArray", _type.isByteArray()) ("storageSize", _type.baseType()->storageSize().str()) ("storageBytes", toString(_type.baseType()->storageBytes())) + ("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes())) .render(); }); } @@ -1228,7 +1289,7 @@ string YulUtilFunctions::memoryArrayIndexAccessFunction(ArrayType const& _type) return Whiskers(R"( function (baseRef, index) -> addr { if iszero(lt(index, (baseRef))) { - invalid() + () } let offset := mul(index, ) @@ -1239,6 +1300,7 @@ string YulUtilFunctions::memoryArrayIndexAccessFunction(ArrayType const& _type) } )") ("functionName", functionName) + ("panic", panicFunction()) ("arrayLen", arrayLengthFunction(_type)) ("stride", to_string(_type.memoryStride())) ("dynamicallySized", _type.isDynamicallySized()) @@ -1253,7 +1315,7 @@ string YulUtilFunctions::calldataArrayIndexAccessFunction(ArrayType const& _type return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( function (base_ref, length, index) -> addr, len { - if iszero(lt(index, length)) { invalid() } + if iszero(lt(index, length)) { () } addr := add(base_ref, mul(index, )) addr, len := (base_ref, addr) @@ -1261,6 +1323,7 @@ string YulUtilFunctions::calldataArrayIndexAccessFunction(ArrayType const& _type } )") ("functionName", functionName) + ("panic", panicFunction()) ("stride", to_string(_type.calldataStride())) ("dynamicallySized", _type.isDynamicallySized()) ("dynamicallyEncodedBase", _type.baseType()->isDynamicallyEncoded()) @@ -1806,12 +1869,13 @@ string YulUtilFunctions::allocationFunction() memPtr := mload() let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { () } mstore(, newFreePtr) } )") - ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) ("functionName", functionName) + ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) + ("panic", panicFunction()) .render(); }); } @@ -2381,7 +2445,7 @@ string YulUtilFunctions::validatorFunction(Type const& _type, bool _revertOnFail if (_revertOnFailure) templ("failure", "revert(0, 0)"); else - templ("failure", "invalid()"); + templ("failure", panicFunction() + "()"); switch (_type.category()) { @@ -2492,11 +2556,12 @@ std::string YulUtilFunctions::decrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { value := (value) - if (value, ) { revert(0,0) } + if (value, ) { () } ret := sub(value, 1) } )") ("functionName", functionName) + ("panic", panicFunction()) ("minval", toCompactHexWithPrefix(minintval)) ("lt", type.isSigned() ? "slt" : "lt") ("cleanupFunction", cleanupFunction(_type)) @@ -2522,13 +2587,14 @@ std::string YulUtilFunctions::incrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { value := (value) - if (value, ) { revert(0,0) } + if (value, ) { () } ret := add(value, 1) } )") ("functionName", functionName) ("maxval", toCompactHexWithPrefix(maxintval)) ("gt", type.isSigned() ? "sgt" : "gt") + ("panic", panicFunction()) ("cleanupFunction", cleanupFunction(_type)) .render(); }); @@ -2547,13 +2613,14 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { value := (value) - if slt(value, ) { revert(0,0) } + if slt(value, ) { () } ret := sub(0, value) } )") ("functionName", functionName) ("minval", toCompactHexWithPrefix(minintval)) ("cleanupFunction", cleanupFunction(_type)) + ("panic", panicFunction()) .render(); }); } @@ -2889,6 +2956,20 @@ string YulUtilFunctions::revertReasonIfDebug(string const& _message) return revertReasonIfDebug(m_revertStrings, _message); } +string YulUtilFunctions::panicFunction() +{ + string functionName = "panic_error"; + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function () { + invalid() + } + )") + ("functionName", functionName) + .render(); + }); +} + string YulUtilFunctions::tryDecodeErrorMessageFunction() { string const functionName = "try_decode_error_message"; diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 8394c33af..5437114f7 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -140,6 +140,10 @@ public: /// signature: (base, exponent, min, max) -> power std::string overflowCheckedSignedExpFunction(); + /// Helper function for the two checked exponentiation functions. + /// signature: (power, base, exponent, max) -> power + std::string overflowCheckedExpLoopFunction(); + /// @returns the name of a function that fetches the length of the given /// array /// signature: (array) -> length @@ -369,6 +373,10 @@ public: std::string revertReasonIfDebug(std::string const& _message = ""); + /// Executes the invalid opcode. + /// Might use revert with special error code in the future. + std::string panicFunction(); + /// Returns the name of a function that decodes an error message. /// signature: () -> arrayPtr /// diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index a833fdfa5..8f102dfda 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -142,6 +142,9 @@ public: std::set& subObjectsCreated() { return m_subObjects; } + bool inlineAssemblySeen() const { return m_inlineAssemblySeen; } + void setInlineAssemblySeen() { m_inlineAssemblySeen = true; } + private: langutil::EVMVersion m_evmVersion; RevertStrings m_revertStrings; @@ -159,6 +162,9 @@ private: MultiUseYulFunctionCollector m_functions; size_t m_varCounter = 0; + /// Flag indicating whether any inline assembly block was seen. + bool m_inlineAssemblySeen = false; + /// Function definitions queued for code generation. They're the Solidity functions whose calls /// were discovered by the IR generator during AST traversal. /// Note that the queue gets filled in a lazy way - new definitions can be added while the diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 8fb932d01..b1ab9dda4 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -92,7 +92,7 @@ string IRGenerator::generate( Whiskers t(R"( object "" { code { - + let := () @@ -103,7 +103,7 @@ string IRGenerator::generate( } object "" { code { - + } @@ -118,7 +118,6 @@ string IRGenerator::generate( m_context.registerImmutableVariable(*var); t("CreationObject", IRNames::creationObject(_contract)); - t("memoryInit", memoryInit()); t("notLibrary", !_contract.isLibrary()); FunctionDefinition const* constructor = _contract.constructor(); @@ -144,6 +143,10 @@ string IRGenerator::generate( t("functions", m_context.functionCollector().requestedFunctions()); t("subObjects", subObjectSources(m_context.subObjectsCreated())); + // This has to be called only after all other code generation for the creation object is complete. + bool creationInvolvesAssembly = m_context.inlineAssemblySeen(); + t("memoryInitCreation", memoryInit(!creationInvolvesAssembly)); + resetContext(_contract); // NOTE: Function pointers can be passed from creation code via storage variables. We need to @@ -158,13 +161,17 @@ string IRGenerator::generate( generateInternalDispatchFunctions(); t("runtimeFunctions", m_context.functionCollector().requestedFunctions()); t("runtimeSubObjects", subObjectSources(m_context.subObjectsCreated())); + + // This has to be called only after all other code generation for the runtime object is complete. + bool runtimeInvolvesAssembly = m_context.inlineAssemblySeen(); + t("memoryInitRuntime", memoryInit(!runtimeInvolvesAssembly)); return t.render(); } string IRGenerator::generate(Block const& _block) { IRGeneratorForStatements generator(m_context, m_utils); - _block.accept(generator); + generator.generate(_block); return generator.code(); } @@ -197,10 +204,11 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions() := () } - default { invalid() } + default { () } } )"); templ("functionName", funName); + templ("panic", m_utils.panicFunction()); templ("in", suffixedVariableNameList("in_", 0, arity.in)); templ("out", suffixedVariableNameList("out_", 0, arity.out)); @@ -651,16 +659,22 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) return t.render(); } -string IRGenerator::memoryInit() +string IRGenerator::memoryInit(bool _useMemoryGuard) { // This function should be called at the beginning of the EVM call frame // 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{ + _useMemoryGuard ? + "mstore(, memoryguard())" : + "mstore(, )" + } ("memPtr", to_string(CompilerUtils::freeMemoryPointer)) - ("freeMemoryStart", to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory())) - .render(); + ( + "freeMemoryStart", + to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory()) + ).render(); } void IRGenerator::resetContext(ContractDefinition const& _contract) diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index e57b8535e..94433912d 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -100,7 +100,9 @@ private: std::string dispatchRoutine(ContractDefinition const& _contract); - std::string memoryInit(); + /// @a _useMemoryGuard If true, use a memory guard, allowing the optimiser + /// to perform memory optimizations. + std::string memoryInit(bool _useMemoryGuard); void resetContext(ContractDefinition const& _contract); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index cacfade33..338f0eb3e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -38,6 +38,8 @@ #include #include +#include + #include #include #include @@ -152,70 +154,130 @@ string IRGeneratorForStatements::code() const return m_code.str(); } +void IRGeneratorForStatements::generate(Block const& _block) +{ + try + { + _block.accept(*this); + } + catch (langutil::UnimplementedFeatureError const& _error) + { + if (!boost::get_error_info(_error)) + _error << langutil::errinfo_sourceLocation(m_currentLocation); + throw _error; + } +} + void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _varDecl) { - solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable."); - solAssert(!_varDecl.isConstant(), ""); - if (!_varDecl.value()) - return; + try + { + setLocation(_varDecl); - _varDecl.value()->accept(*this); - writeToLValue( - _varDecl.immutable() ? - IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} : - IRLValue{*_varDecl.annotation().type, IRLValue::Storage{ - util::toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first), - m_context.storageLocationOfStateVariable(_varDecl).second - }}, - *_varDecl.value() - ); + solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable."); + solAssert(!_varDecl.isConstant(), ""); + 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.storageLocationOfStateVariable(_varDecl).first), + m_context.storageLocationOfStateVariable(_varDecl).second + }}, + *_varDecl.value() + ); + } + catch (langutil::UnimplementedFeatureError const& _error) + { + if (!boost::get_error_info(_error)) + _error << langutil::errinfo_sourceLocation(m_currentLocation); + throw _error; + } } void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl) { - solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable."); + try + { + setLocation(_varDecl); - auto const* type = _varDecl.type(); - if (auto const* refType = dynamic_cast(type)) - if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer()) - return; + solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable."); - IRVariable zero = zeroValue(*type); - assign(m_context.localVariable(_varDecl), zero); + auto const* type = _varDecl.type(); + if (auto const* refType = dynamic_cast(type)) + if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer()) + return; + + IRVariable zero = zeroValue(*type); + assign(m_context.localVariable(_varDecl), zero); + } + catch (langutil::UnimplementedFeatureError const& _error) + { + if (!boost::get_error_info(_error)) + _error << langutil::errinfo_sourceLocation(m_currentLocation); + throw _error; + } } IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expression, Type const& _targetType) { - _expression.accept(*this); - IRVariable variable{m_context.newYulVariable(), _targetType}; - define(variable, _expression); - return variable; + try + { + setLocation(_expression); + + _expression.accept(*this); + IRVariable variable{m_context.newYulVariable(), _targetType}; + define(variable, _expression); + return variable; + } + catch (langutil::UnimplementedFeatureError const& _error) + { + if (!boost::get_error_info(_error)) + _error << langutil::errinfo_sourceLocation(m_currentLocation); + throw _error; + } } string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant) { - string functionName = IRNames::constantValueFunction(_constant); - 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()); + try + { + setLocation(_constant); - return templ.render(); - }); + string functionName = IRNames::constantValueFunction(_constant); + 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(); + }); + } + catch (langutil::UnimplementedFeatureError const& _error) + { + if (!boost::get_error_info(_error)) + _error << langutil::errinfo_sourceLocation(m_currentLocation); + throw _error; + } } void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement) { + setLocation(_varDeclStatement); + if (Expression const* expression = _varDeclStatement.initialValue()) { if (_varDeclStatement.declarations().size() > 1) @@ -249,14 +311,22 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional) { _conditional.condition().accept(*this); + setLocation(_conditional); + string condition = expressionAsType(_conditional.condition(), *TypeProvider::boolean()); declare(_conditional); m_code << "switch " << condition << "\n" "case 0 {\n"; + _conditional.falseExpression().accept(*this); + setLocation(_conditional); + assign(_conditional, _conditional.falseExpression()); m_code << "}\n" "default {\n"; + _conditional.trueExpression().accept(*this); + setLocation(_conditional); + assign(_conditional, _conditional.trueExpression()); m_code << "}\n"; @@ -266,6 +336,7 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional) bool IRGeneratorForStatements::visit(Assignment const& _assignment) { _assignment.rightHandSide().accept(*this); + setLocation(_assignment); Token assignmentOperator = _assignment.assignmentOperator(); Token binaryOperator = @@ -283,6 +354,7 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) IRVariable value = convert(_assignment.rightHandSide(), *rightIntermediateType); _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); + setLocation(_assignment); if (assignmentOperator != Token::Assign) { @@ -323,6 +395,8 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) { + setLocation(_tuple); + if (_tuple.isInlineArray()) { auto const& arrayType = dynamic_cast(*_tuple.annotation().type); @@ -339,6 +413,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) { Expression const& component = *_tuple.components()[i]; component.accept(*this); + setLocation(_tuple); IRVariable converted = convert(component, baseType); m_code << m_utils.writeToMemoryFunction(baseType) << @@ -358,6 +433,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) { solAssert(_tuple.components().front(), ""); _tuple.components().front()->accept(*this); + setLocation(_tuple); if (willBeWrittenTo) solAssert(!!m_currentLValue, ""); else @@ -370,6 +446,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) if (auto const& component = _tuple.components()[i]) { component->accept(*this); + setLocation(_tuple); if (willBeWrittenTo) { solAssert(!!m_currentLValue, ""); @@ -395,17 +472,20 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement) { _ifStatement.condition().accept(*this); + setLocation(_ifStatement); string condition = expressionAsType(_ifStatement.condition(), *TypeProvider::boolean()); if (_ifStatement.falseStatement()) { m_code << "switch " << condition << "\n" "case 0 {\n"; _ifStatement.falseStatement()->accept(*this); + setLocation(_ifStatement); m_code << "}\n" "default {\n"; } else m_code << "if " << condition << " {\n"; _ifStatement.trueStatement().accept(*this); + setLocation(_ifStatement); m_code << "}\n"; return false; @@ -413,6 +493,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement) bool IRGeneratorForStatements::visit(ForStatement const& _forStatement) { + setLocation(_forStatement); generateLoop( _forStatement.body(), _forStatement.condition(), @@ -425,6 +506,7 @@ bool IRGeneratorForStatements::visit(ForStatement const& _forStatement) bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement) { + setLocation(_whileStatement); generateLoop( _whileStatement.body(), &_whileStatement.condition(), @@ -436,20 +518,23 @@ bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement) return false; } -bool IRGeneratorForStatements::visit(Continue const&) +bool IRGeneratorForStatements::visit(Continue const& _continue) { + setLocation(_continue); m_code << "continue\n"; return false; } -bool IRGeneratorForStatements::visit(Break const&) +bool IRGeneratorForStatements::visit(Break const& _break) { + setLocation(_break); m_code << "break\n"; return false; } void IRGeneratorForStatements::endVisit(Return const& _return) { + setLocation(_return); if (Expression const* value = _return.expression()) { solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer."); @@ -466,6 +551,7 @@ void IRGeneratorForStatements::endVisit(Return const& _return) void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation) { + setLocation(_unaryOperation); Type const& resultType = type(_unaryOperation); Token const op = _unaryOperation.getOperator(); @@ -551,6 +637,8 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation) bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) { + setLocation(_binOp); + solAssert(!!_binOp.annotation().commonType, ""); TypePointer commonType = _binOp.annotation().commonType; langutil::Token op = _binOp.getOperator(); @@ -570,6 +658,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) _binOp.leftExpression().accept(*this); _binOp.rightExpression().accept(*this); + setLocation(_binOp); if (TokenTraits::isCompareOp(op)) { @@ -629,6 +718,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) { + setLocation(_functionCall); FunctionTypePointer functionType = dynamic_cast(&type(_functionCall.expression())); if ( functionType && @@ -643,6 +733,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { + setLocation(_functionCall); auto functionCallKind = *_functionCall.annotation().kind; if (functionCallKind == FunctionCallKind::TypeConversion) @@ -1156,8 +1247,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2])); define(modulus, *arguments[2]); - Whiskers templ("if iszero() { invalid() }\n"); - m_code << templ("modulus", modulus.name()).render(); + Whiskers templ("if iszero() { () }\n"); + templ("modulus", modulus.name()); + templ("panic", m_utils.panicFunction()); + m_code << templ.render(); string args; for (size_t i = 0; i < 2; ++i) @@ -1234,7 +1327,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) Whiskers t(R"( let := () let := add(, datasize("")) - if or(gt(, 0xffffffffffffffff), lt(, )) { revert(0, 0) } + if or(gt(, 0xffffffffffffffff), lt(, )) { () } datacopy(, dataoffset(""), datasize("")) := () @@ -1249,6 +1342,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) t("allocateTemporaryMemory", m_utils.allocationTemporaryMemoryFunction()); t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction()); t("object", IRNames::creationObject(*contract)); + t("panic", m_utils.panicFunction()); t("abiEncode", m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) ); @@ -1360,6 +1454,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) { + setLocation(_options); FunctionType const& previousType = dynamic_cast(*_options.expression().annotation().type); solUnimplementedAssert(!previousType.bound(), ""); @@ -1379,6 +1474,7 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { + setLocation(_memberAccess); ASTString const& member = _memberAccess.memberName(); auto memberFunctionType = dynamic_cast(_memberAccess.annotation().type); Type::Category objectCategory = _memberAccess.expression().annotation().type->category(); @@ -1549,10 +1645,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); - uint64_t result{0}; - for (auto const& function: contract.interfaceFunctionList(false)) - result ^= fromBigEndian(function.first.ref()); - define(_memberAccess) << formatNumber(u256{result} << (256 - 32)) << "\n"; + define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n"; } else if (member == "min" || member == "max") { @@ -1767,6 +1860,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm) { + setLocation(_inlineAsm); + m_context.setInlineAssemblySeen(); CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences}; yul::Statement modified = bodyCopier(_inlineAsm.operations()); @@ -1781,6 +1876,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm) void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) { + setLocation(_indexAccess); Type const& baseType = *_indexAccess.baseExpression().annotation().type; if (baseType.category() == Type::Category::Mapping) @@ -1894,11 +1990,12 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) IRVariable index{m_context.newYulVariable(), *TypeProvider::uint256()}; define(index, *_indexAccess.indexExpression()); m_code << Whiskers(R"( - if iszero(lt(, )) { invalid() } + if iszero(lt(, )) { () } let := (byte(, )) )") ("index", index.name()) ("length", to_string(fixedBytesType.numBytes())) + ("panic", m_utils.panicFunction()) ("array", IRVariable(_indexAccess.baseExpression()).name()) ("shl248", m_utils.shiftLeftFunction(256 - 8)) ("result", IRVariable(_indexAccess).name()) @@ -1916,6 +2013,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAccess) { + setLocation(_indexRangeAccess); Type const& baseType = *_indexRangeAccess.baseExpression().annotation().type; solAssert( baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice, @@ -1962,6 +2060,7 @@ void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAcces void IRGeneratorForStatements::endVisit(Identifier const& _identifier) { + setLocation(_identifier); Declaration const* declaration = _identifier.annotation().referencedDeclaration; if (MagicVariableDeclaration const* magicVar = dynamic_cast(declaration)) { @@ -2020,6 +2119,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) bool IRGeneratorForStatements::visit(Literal const& _literal) { + setLocation(_literal); Type const& literalType = type(_literal); switch (literalType.category()) @@ -2042,6 +2142,7 @@ void IRGeneratorForStatements::handleVariableReference( Expression const& _referencingExpression ) { + setLocation(_referencingExpression); if (_variable.isStateVariable() && _variable.isConstant()) define(_referencingExpression) << constantValueFunction(_variable) << "()\n"; else if (_variable.isStateVariable() && _variable.immutable()) @@ -2483,6 +2584,7 @@ void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _b solAssert(op == Token::Or || op == Token::And, ""); _binOp.leftExpression().accept(*this); + setLocation(_binOp); IRVariable value(_binOp); define(value, _binOp.leftExpression()); @@ -2491,6 +2593,7 @@ void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _b else m_code << "if " << value.name() << " {\n"; _binOp.rightExpression().accept(*this); + setLocation(_binOp); assign(value, _binOp.rightExpression()); m_code << "}\n"; } @@ -2690,6 +2793,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement) { Expression const& externalCall = _tryStatement.externalCall(); externalCall.accept(*this); + setLocation(_tryStatement); m_code << "switch iszero(" << IRNames::trySuccessConditionVariable(externalCall) << ")\n"; @@ -2710,6 +2814,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement) } successClause.block().accept(*this); + setLocation(_tryStatement); m_code << "}\n"; m_code << "default { // failure case\n"; @@ -2800,3 +2905,8 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause) _clause.block().accept(*this); return false; } + +void IRGeneratorForStatements::setLocation(ASTNode const& _node) +{ + m_currentLocation = _node.location(); +} diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 09c9c7d27..3d87eae57 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -47,6 +47,9 @@ public: std::string code() const; + /// Generate the code for the statements in the block; + void generate(Block const& _block); + /// Generates code to initialize the given state variable. void initializeStateVar(VariableDeclaration const& _varDecl); /// Generates code to initialize the given local variable. @@ -179,10 +182,13 @@ private: static Type const& type(Expression const& _expression); + void setLocation(ASTNode const& _node); + std::ostringstream m_code; IRGenerationContext& m_context; YulUtilFunctions& m_utils; std::optional m_currentLValue; + langutil::SourceLocation m_currentLocation; }; } diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index 503f48da8..0f3d899a3 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -580,7 +580,7 @@ pair, vector> BMC::modelExpressions() auto const& type = var.second->type(); if ( type->isValueType() && - smt::smtKind(type->category()) != smtutil::Kind::Function + smt::smtKind(*type) != smtutil::Kind::Function ) { expressionsToEvaluate.emplace_back(var.second->currentValue()); @@ -836,11 +836,11 @@ void BMC::checkCondition( case smtutil::CheckResult::SATISFIABLE: { std::ostringstream message; - message << _description << " happens here"; + message << "BMC: " << _description << " happens here."; if (_callStack.size()) { std::ostringstream modelMessage; - modelMessage << " for:\n"; + modelMessage << "\nCounterexample:\n"; solAssert(values.size() == expressionNames.size(), ""); map sortedModel; for (size_t i = 0; i < values.size(); ++i) @@ -859,22 +859,19 @@ void BMC::checkCondition( ); } else - { - message << "."; m_errorReporter.warning(6084_error, _location, message.str(), secondaryLocation); - } break; } case smtutil::CheckResult::UNSATISFIABLE: break; case smtutil::CheckResult::UNKNOWN: - m_errorReporter.warning(_errorMightHappen, _location, _description + " might happen here.", secondaryLocation); + m_errorReporter.warning(_errorMightHappen, _location, "BMC: " + _description + " might happen here.", secondaryLocation); break; case smtutil::CheckResult::CONFLICTING: - m_errorReporter.warning(1584_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_errorReporter.warning(1584_error, _location, "BMC: At least two SMT solvers provided conflicting answers. Results might not be sound."); break; case smtutil::CheckResult::ERROR: - m_errorReporter.warning(1823_error, _location, "Error trying to invoke SMT solver."); + m_errorReporter.warning(1823_error, _location, "BMC: Error trying to invoke SMT solver."); break; } @@ -922,13 +919,13 @@ void BMC::checkBooleanNotConstant( if (positiveResult == smtutil::CheckResult::SATISFIABLE) { solAssert(negatedResult == smtutil::CheckResult::UNSATISFIABLE, ""); - description = "Condition is always true."; + description = "BMC: Condition is always true."; } else { solAssert(positiveResult == smtutil::CheckResult::UNSATISFIABLE, ""); solAssert(negatedResult == smtutil::CheckResult::SATISFIABLE, ""); - description = "Condition is always false."; + description = "BMC: Condition is always false."; } m_errorReporter.warning( 6838_error, diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index f6a3b5aae..0bac096f3 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -22,6 +22,7 @@ #include #endif +#include #include #include @@ -39,54 +40,33 @@ using namespace solidity::util; using namespace solidity::langutil; using namespace solidity::smtutil; using namespace solidity::frontend; +using namespace solidity::frontend::smt; CHC::CHC( - smt::EncodingContext& _context, + EncodingContext& _context, ErrorReporter& _errorReporter, - map const& _smtlib2Responses, - ReadCallback::Callback const& _smtCallback, - [[maybe_unused]] smtutil::SMTSolverChoice _enabledSolvers + [[maybe_unused]] map const& _smtlib2Responses, + [[maybe_unused]] ReadCallback::Callback const& _smtCallback, + SMTSolverChoice _enabledSolvers ): SMTEncoder(_context), m_outerErrorReporter(_errorReporter), m_enabledSolvers(_enabledSolvers) { -#ifdef HAVE_Z3 - if (_enabledSolvers.z3) - m_interface = make_unique(); + bool usesZ3 = _enabledSolvers.z3; +#ifndef HAVE_Z3 + usesZ3 = false; #endif - if (!m_interface) - m_interface = make_unique(_smtlib2Responses, _smtCallback); + if (!usesZ3) + m_interface = make_unique(_smtlib2Responses, _smtCallback); } void CHC::analyze(SourceUnit const& _source) { solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), ""); - bool usesZ3 = false; -#ifdef HAVE_Z3 - usesZ3 = m_enabledSolvers.z3; - if (usesZ3) - { - auto z3Interface = dynamic_cast(m_interface.get()); - solAssert(z3Interface, ""); - m_context.setSolver(z3Interface->z3Interface()); - } -#endif - if (!usesZ3) - { - auto smtlib2Interface = dynamic_cast(m_interface.get()); - solAssert(smtlib2Interface, ""); - m_context.setSolver(smtlib2Interface->smtlib2Interface()); - } - m_context.clear(); - m_context.setAssertionAccumulation(false); - resetSourceAnalysis(); - m_genesisPredicate = createSymbolicBlock(arity0FunctionSort(), "genesis"); - addRule(genesis(), "genesis"); - set sources; sources.insert(&_source); for (auto const& source: _source.referencedSourceUnits(true)) @@ -101,7 +81,7 @@ void CHC::analyze(SourceUnit const& _source) vector CHC::unhandledQueries() const { - if (auto smtlib2 = dynamic_cast(m_interface.get())) + if (auto smtlib2 = dynamic_cast(m_interface.get())) return smtlib2->unhandledQueries(); return {}; @@ -114,13 +94,15 @@ bool CHC::visit(ContractDefinition const& _contract) initContract(_contract); m_stateVariables = SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract); - m_stateSorts = stateSorts(_contract); clearIndices(&_contract); - string suffix = _contract.name() + "_" + to_string(_contract.id()); - m_constructorSummaryPredicate = createSymbolicBlock(constructorSort(), "summary_constructor_" + suffix, &_contract); - m_implicitConstructorPredicate = createSymbolicBlock(arity0FunctionSort(), "implicit_constructor_" + suffix, &_contract); + solAssert(m_currentContract, ""); + m_constructorSummaryPredicate = createSymbolicBlock( + constructorSort(*m_currentContract), + "summary_constructor_" + contractSuffix(_contract), + &_contract + ); auto stateExprs = currentStateVariables(); setCurrentBlock(*m_interfaces.at(m_currentContract), &stateExprs); @@ -130,8 +112,13 @@ bool CHC::visit(ContractDefinition const& _contract) void CHC::endVisit(ContractDefinition const& _contract) { - auto implicitConstructor = (*m_implicitConstructorPredicate)({}); - connectBlocks(genesis(), implicitConstructor); + auto implicitConstructorPredicate = createSymbolicBlock( + implicitConstructorSort(), + "implicit_constructor_" + contractSuffix(_contract), + &_contract + ); + auto implicitConstructor = (*implicitConstructorPredicate)({}); + addRule(implicitConstructor, implicitConstructor.name); m_currentBlock = implicitConstructor; m_context.addAssertion(m_error.currentValue() == 0); @@ -156,7 +143,7 @@ bool CHC::visit(FunctionDefinition const& _function) { if (!_function.isImplemented()) { - connectBlocks(genesis(), summary(_function)); + addRule(summary(_function), "summary_function_" + to_string(_function.id())); return false; } @@ -184,7 +171,7 @@ bool CHC::visit(FunctionDefinition const& _function) if (_function.isConstructor()) connectBlocks(m_currentBlock, functionPred); else - connectBlocks(genesis(), functionPred); + addRule(functionPred, functionPred.name); m_context.addAssertion(m_error.currentValue() == 0); for (auto const* var: m_stateVariables) @@ -226,7 +213,12 @@ void CHC::endVisit(FunctionDefinition const& _function) if (_function.isConstructor()) { string suffix = m_currentContract->name() + "_" + to_string(m_currentContract->id()); - auto constructorExit = createSymbolicBlock(constructorSort(), "constructor_exit_" + suffix, m_currentContract); + solAssert(m_currentContract, ""); + auto constructorExit = createSymbolicBlock( + constructorSort(*m_currentContract), + "constructor_exit_" + suffix, + m_currentContract + ); connectBlocks(m_currentBlock, predicate(*constructorExit, currentFunctionVariables(*m_currentContract))); clearIndices(m_currentContract, m_currentFunction); @@ -588,7 +580,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop) auto memberAccess = dynamic_cast(&_arrayPop.expression()); solAssert(memberAccess, ""); - auto symbArray = dynamic_pointer_cast(m_context.expression(memberAccess->expression())); + auto symbArray = dynamic_pointer_cast(m_context.expression(memberAccess->expression())); solAssert(symbArray, ""); auto previousError = m_error.currentValue(); @@ -676,11 +668,34 @@ void CHC::resetSourceAnalysis() m_interfaces.clear(); m_nondetInterfaces.clear(); Predicate::reset(); + m_blockCounter = 0; + + bool usesZ3 = false; +#ifdef HAVE_Z3 + usesZ3 = m_enabledSolvers.z3; + if (usesZ3) + { + /// z3::fixedpoint does not have a reset mechanism, so we need to create another. + m_interface.reset(new Z3CHCInterface()); + auto z3Interface = dynamic_cast(m_interface.get()); + solAssert(z3Interface, ""); + m_context.setSolver(z3Interface->z3Interface()); + } +#endif + if (!usesZ3) + { + auto smtlib2Interface = dynamic_cast(m_interface.get()); + smtlib2Interface->reset(); + solAssert(smtlib2Interface, ""); + m_context.setSolver(smtlib2Interface->smtlib2Interface()); + } + + m_context.clear(); + m_context.setAssertionAccumulation(false); } void CHC::resetContractAnalysis() { - m_stateSorts.clear(); m_stateVariables.clear(); m_unknownFunctionCallSeen = false; m_breakDest = nullptr; @@ -737,117 +752,18 @@ set CHC::transactionAssertions(ASTN return assertions; } -vector CHC::stateSorts(ContractDefinition const& _contract) +SortPointer CHC::sort(FunctionDefinition const& _function) { - return applyMap( - SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract), - [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); } - ); + return functionSort(_function, m_currentContract); } -smtutil::SortPointer CHC::constructorSort() -{ - solAssert(m_currentContract, ""); - if (auto const* constructor = m_currentContract->constructor()) - return sort(*constructor); - - return make_shared( - vector{smtutil::SortProvider::uintSort} + m_stateSorts, - smtutil::SortProvider::boolSort - ); -} - -smtutil::SortPointer CHC::interfaceSort() -{ - solAssert(m_currentContract, ""); - return interfaceSort(*m_currentContract); -} - -smtutil::SortPointer CHC::nondetInterfaceSort() -{ - solAssert(m_currentContract, ""); - return nondetInterfaceSort(*m_currentContract); -} - -smtutil::SortPointer CHC::interfaceSort(ContractDefinition const& _contract) -{ - return make_shared( - stateSorts(_contract), - smtutil::SortProvider::boolSort - ); -} - -smtutil::SortPointer CHC::nondetInterfaceSort(ContractDefinition const& _contract) -{ - auto sorts = stateSorts(_contract); - return make_shared( - sorts + sorts, - smtutil::SortProvider::boolSort - ); -} - -smtutil::SortPointer CHC::arity0FunctionSort() const -{ - return make_shared( - vector(), - smtutil::SortProvider::boolSort - ); -} - -/// A function in the symbolic CFG requires: -/// - Index of failed assertion. 0 means no assertion failed. -/// - 2 sets of state variables: -/// - State variables at the beginning of the current function, immutable -/// - Current state variables -/// At the beginning of the function these must equal set 1 -/// - 2 sets of input variables: -/// - Input variables at the beginning of the current function, immutable -/// - Current input variables -/// At the beginning of the function these must equal set 1 -/// - 1 set of output variables -smtutil::SortPointer CHC::sort(FunctionDefinition const& _function) -{ - auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }; - auto inputSorts = applyMap(_function.parameters(), smtSort); - auto outputSorts = applyMap(_function.returnParameters(), smtSort); - return make_shared( - vector{smtutil::SortProvider::uintSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts, - smtutil::SortProvider::boolSort - ); -} - -smtutil::SortPointer CHC::sort(ASTNode const* _node) +SortPointer CHC::sort(ASTNode const* _node) { if (auto funDef = dynamic_cast(_node)) return sort(*funDef); - auto fSort = dynamic_pointer_cast(sort(*m_currentFunction)); - solAssert(fSort, ""); - - auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }; - return make_shared( - fSort->domain + applyMap(m_currentFunction->localVariables(), smtSort), - smtutil::SortProvider::boolSort - ); -} - -smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, ContractDefinition const& _contract) -{ - auto stateVariables = SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract); - auto sorts = stateSorts(_contract); - - auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }; - auto inputSorts = applyMap(_function.parameters(), smtSort); - auto outputSorts = applyMap(_function.returnParameters(), smtSort); - return make_shared( - vector{smtutil::SortProvider::uintSort} + - sorts + - inputSorts + - sorts + - inputSorts + - outputSorts, - smtutil::SortProvider::boolSort - ); + solAssert(m_currentFunction, ""); + return functionBodySort(*m_currentFunction, m_currentContract); } Predicate const* CHC::createSymbolicBlock(SortPointer _sort, string const& _name, ASTNode const* _node) @@ -861,27 +777,23 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source) { for (auto const& node: _source.nodes()) if (auto const* contract = dynamic_cast(node.get())) + { + string suffix = contract->name() + "_" + to_string(contract->id()); + m_interfaces[contract] = createSymbolicBlock(interfaceSort(*contract), "interface_" + suffix); + m_nondetInterfaces[contract] = createSymbolicBlock(nondetInterfaceSort(*contract), "nondet_interface_" + suffix); + + for (auto const* var: stateVariablesIncludingInheritedAndPrivate(*contract)) + if (!m_context.knownVariable(*var)) + createVariable(*var); + + /// Base nondeterministic interface that allows + /// 0 steps to be taken, used as base for the inductive + /// rule for each function. + auto const& iface = *m_nondetInterfaces.at(contract); + auto state0 = stateVariablesAtIndex(0, *contract); + addRule(iface(state0 + state0), "base_nondet"); + for (auto const* base: contract->annotation().linearizedBaseContracts) - { - for (auto const* var: SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*base)) - if (!m_context.knownVariable(*var)) - createVariable(*var); - - if (!m_interfaces.count(base)) - { - solAssert(!m_nondetInterfaces.count(base), ""); - string suffix = base->name() + "_" + to_string(base->id()); - m_interfaces.emplace(base, createSymbolicBlock(interfaceSort(*base), "interface_" + suffix, base)); - m_nondetInterfaces.emplace(base, createSymbolicBlock(nondetInterfaceSort(*base), "nondet_interface_" + suffix, base)); - - /// Base nondeterministic interface that allows - /// 0 steps to be taken, used as base for the inductive - /// rule for each function. - auto const* iface = m_nondetInterfaces.at(base); - auto state0 = stateVariablesAtIndex(0, *base); - addRule((*iface)(state0 + state0), "base_nondet"); - } - for (auto const* function: base->definedFunctions()) { for (auto var: function->parameters()) @@ -900,13 +812,11 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source) !base->isInterface() ) { - auto state1 = stateVariablesAtIndex(1, *base); - auto state2 = stateVariablesAtIndex(2, *base); + auto state1 = stateVariablesAtIndex(1, *contract); + auto state2 = stateVariablesAtIndex(2, *contract); - auto const* iface = m_nondetInterfaces.at(base); - auto state0 = stateVariablesAtIndex(0, *base); - auto nondetPre = (*iface)(state0 + state1); - auto nondetPost = (*iface)(state0 + state2); + auto nondetPre = iface(state0 + state1); + auto nondetPost = iface(state0 + state2); vector args{m_error.currentValue()}; args += state1 + @@ -915,10 +825,10 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source) applyMap(function->parameters(), [this](auto _var) { return valueAtIndex(*_var, 1); }) + applyMap(function->returnParameters(), [this](auto _var) { return valueAtIndex(*_var, 1); }); - connectBlocks(nondetPre, nondetPost, (*m_summaries.at(base).at(function))(args)); + connectBlocks(nondetPre, nondetPost, (*m_summaries.at(contract).at(function))(args)); } - } } + } } smtutil::Expression CHC::interface() @@ -991,7 +901,7 @@ Predicate const* CHC::createBlock(ASTNode const* _node, string const& _prefix) Predicate const* CHC::createSummaryBlock(FunctionDefinition const& _function, ContractDefinition const& _contract) { auto block = createSymbolicBlock( - summarySort(_function, _contract), + functionSort(_function, &_contract), "summary_" + uniquePrefix() + "_" + predicateName(&_function, &_contract), &_function ); @@ -1161,14 +1071,14 @@ void CHC::addRule(smtutil::Expression const& _rule, string const& _ruleName) m_interface->addRule(_rule, _ruleName); } -pair CHC::query(smtutil::Expression const& _query, langutil::SourceLocation const& _location) +pair CHC::query(smtutil::Expression const& _query, langutil::SourceLocation const& _location) { - smtutil::CheckResult result; + CheckResult result; CHCSolverInterface::CexGraph cex; tie(result, cex) = m_interface->query(_query); switch (result) { - case smtutil::CheckResult::SATISFIABLE: + case CheckResult::SATISFIABLE: { #ifdef HAVE_Z3 // Even though the problem is SAT, Spacer's pre processing makes counterexamples incomplete. @@ -1177,26 +1087,26 @@ pair CHC::query(smtutil::Exp solAssert(spacer, ""); spacer->setSpacerOptions(false); - smtutil::CheckResult resultNoOpt; + CheckResult resultNoOpt; CHCSolverInterface::CexGraph cexNoOpt; tie(resultNoOpt, cexNoOpt) = m_interface->query(_query); - if (resultNoOpt == smtutil::CheckResult::SATISFIABLE) + if (resultNoOpt == CheckResult::SATISFIABLE) cex = move(cexNoOpt); spacer->setSpacerOptions(true); #endif break; } - case smtutil::CheckResult::UNSATISFIABLE: + case CheckResult::UNSATISFIABLE: break; - case smtutil::CheckResult::UNKNOWN: + case CheckResult::UNKNOWN: break; - case smtutil::CheckResult::CONFLICTING: - m_outerErrorReporter.warning(1988_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); + case CheckResult::CONFLICTING: + m_outerErrorReporter.warning(1988_error, _location, "CHC: At least two SMT solvers provided conflicting answers. Results might not be sound."); break; - case smtutil::CheckResult::ERROR: - m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver."); + case CheckResult::ERROR: + m_outerErrorReporter.warning(1218_error, _location, "CHC: Error trying to invoke SMT solver."); break; } return {result, cex}; @@ -1210,6 +1120,16 @@ void CHC::addVerificationTarget( smtutil::Expression _errorId ) { + solAssert(m_currentContract || m_currentFunction, ""); + SourceUnit const* source = nullptr; + if (m_currentContract) + source = sourceUnitContaining(*m_currentContract); + else + source = sourceUnitContaining(*m_currentFunction); + solAssert(source, ""); + if (!source->annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker)) + return; + m_verificationTargets.emplace(_scope, CHCVerificationTarget{{_type, _from, _constraints}, _errorId}); } @@ -1251,7 +1171,7 @@ void CHC::checkVerificationTargets() if (target.type == VerificationTarget::Type::PopEmptyArray) { solAssert(dynamic_cast(scope), ""); - satMsg = "Empty array \"pop\" detected here"; + satMsg = "Empty array \"pop\" detected here."; unknownMsg = "Empty array \"pop\" might happen here."; errorReporterId = 2529_error; } @@ -1267,8 +1187,8 @@ void CHC::checkVerificationTargets() if (!intType) intType = TypeProvider::uint256(); - satMsgUnderflow = "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ") happens here"; - satMsgOverflow = "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ") happens here"; + satMsgUnderflow = "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ") happens here."; + satMsgOverflow = "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ") happens here."; if (target.type == VerificationTarget::Type::Underflow) { satMsg = satMsgUnderflow; @@ -1314,7 +1234,7 @@ void CHC::checkAssertTarget(ASTNode const* _scope, CHCVerificationTarget const& solAssert(it != m_errorIds.end(), ""); unsigned errorId = it->second; - checkAndReportTarget(assertion, _target, errorId, 6328_error, "Assertion violation happens here"); + checkAndReportTarget(assertion, _target, errorId, 6328_error, "Assertion violation happens here."); } } @@ -1333,9 +1253,9 @@ void CHC::checkAndReportTarget( createErrorBlock(); connectBlocks(_target.value, error(), _target.constraints && (_target.errorId == _errorId)); auto const& [result, model] = query(error(), _scope->location()); - if (result == smtutil::CheckResult::UNSATISFIABLE) + if (result == CheckResult::UNSATISFIABLE) m_safeTargets[_scope].insert(_target.type); - else if (result == smtutil::CheckResult::SATISFIABLE) + else if (result == CheckResult::SATISFIABLE) { solAssert(!_satMsg.empty(), ""); m_unsafeTargets[_scope].insert(_target.type); @@ -1344,21 +1264,21 @@ void CHC::checkAndReportTarget( m_outerErrorReporter.warning( _errorReporterId, _scope->location(), - _satMsg, - SecondarySourceLocation().append(" for:\n" + *cex, SourceLocation{}) + "CHC: " + _satMsg, + SecondarySourceLocation().append("\nCounterexample:\n" + *cex, SourceLocation{}) ); else m_outerErrorReporter.warning( _errorReporterId, _scope->location(), - _satMsg + "." + "CHC: " + _satMsg ); } else if (!_unknownMsg.empty()) m_outerErrorReporter.warning( _errorReporterId, _scope->location(), - _unknownMsg + "CHC: " + _unknownMsg ); } @@ -1459,7 +1379,11 @@ optional CHC::generateCounterexample(CHCSolverInterface::CexGraph const& /// Recurse on the next interface node which represents the previous transaction /// or stop. if (interfaceId) + { + Predicate const* interfacePredicate = Predicate::predicate(_graph.nodes.at(*interfaceId).first); + solAssert(interfacePredicate && interfacePredicate->isInterface(), ""); node = *interfaceId; + } else break; } @@ -1467,7 +1391,7 @@ optional CHC::generateCounterexample(CHCSolverInterface::CexGraph const& return localState + "\nTransaction trace:\n" + boost::algorithm::join(boost::adaptors::reverse(path), "\n"); } -string CHC::cex2dot(smtutil::CHCSolverInterface::CexGraph const& _cex) +string CHC::cex2dot(CHCSolverInterface::CexGraph const& _cex) { string dot = "digraph {\n"; @@ -1488,6 +1412,11 @@ string CHC::uniquePrefix() return to_string(m_blockCounter++); } +string CHC::contractSuffix(ContractDefinition const& _contract) +{ + return _contract.name() + "_" + to_string(_contract.id()); +} + unsigned CHC::newErrorId(frontend::Expression const& _expr) { unsigned errorId = m_context.newUniqueId(); diff --git a/libsolidity/formal/CHC.h b/libsolidity/formal/CHC.h index d555f19e7..7eee92eb7 100644 --- a/libsolidity/formal/CHC.h +++ b/libsolidity/formal/CHC.h @@ -117,19 +117,8 @@ private: /// Sort helpers. //@{ - static std::vector stateSorts(ContractDefinition const& _contract); - smtutil::SortPointer constructorSort(); - smtutil::SortPointer interfaceSort(); - smtutil::SortPointer nondetInterfaceSort(); - static smtutil::SortPointer interfaceSort(ContractDefinition const& _const); - static smtutil::SortPointer nondetInterfaceSort(ContractDefinition const& _const); - smtutil::SortPointer arity0FunctionSort() const; smtutil::SortPointer sort(FunctionDefinition const& _function); smtutil::SortPointer sort(ASTNode const* _block); - /// @returns the sort of a predicate that represents the summary of _function in the scope of _contract. - /// The _contract is also needed because the same function might be in many contracts due to inheritance, - /// where the sort changes because the set of state variables might change. - static smtutil::SortPointer summarySort(FunctionDefinition const& _function, ContractDefinition const& _contract); //@} /// Predicate helpers. @@ -141,8 +130,6 @@ private: /// in a given _source. void defineInterfacesAndSummaries(SourceUnit const& _source); - /// Genesis predicate. - smtutil::Expression genesis() { return (*m_genesisPredicate)({}); } /// Interface predicate over current variables. smtutil::Expression interface(); smtutil::Expression interface(ContractDefinition const& _contract); @@ -248,10 +235,13 @@ private: /// Misc. //@{ - /// Returns a prefix to be used in a new unique block name + /// @returns a prefix to be used in a new unique block name /// and increases the block counter. std::string uniquePrefix(); + /// @returns a suffix to be used by contract related predicates. + std::string contractSuffix(ContractDefinition const& _contract); + /// @returns a new unique error id associated with _expr and stores /// it into m_errorIds. unsigned newErrorId(Expression const& _expr); @@ -259,13 +249,6 @@ private: /// Predicates. //@{ - /// Genesis predicate. - Predicate const* m_genesisPredicate = nullptr; - - /// Implicit constructor predicate. - /// Explicit constructors are handled as functions. - Predicate const* m_implicitConstructorPredicate = nullptr; - /// Constructor summary predicate, exists after the constructor /// (implicit or explicit) and before the interface. Predicate const* m_constructorSummaryPredicate = nullptr; @@ -293,16 +276,10 @@ private: "error", m_context }; - - /// Maps predicate names to the ASTNodes they came from. - std::map m_symbolFunction; //@} /// Variables. //@{ - /// State variables sorts. - /// Used by all predicates. - std::vector m_stateSorts; /// State variables. /// Used to create all predicates. std::vector m_stateVariables; diff --git a/libsolidity/formal/PredicateSort.cpp b/libsolidity/formal/PredicateSort.cpp new file mode 100644 index 000000000..ffef00f0c --- /dev/null +++ b/libsolidity/formal/PredicateSort.cpp @@ -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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include +#include + +using namespace std; +using namespace solidity::util; +using namespace solidity::smtutil; + +namespace solidity::frontend::smt +{ + +SortPointer interfaceSort(ContractDefinition const& _contract) +{ + return make_shared( + stateSorts(_contract), + SortProvider::boolSort + ); +} + +SortPointer nondetInterfaceSort(ContractDefinition const& _contract) +{ + auto varSorts = stateSorts(_contract); + return make_shared( + varSorts + varSorts, + SortProvider::boolSort + ); +} + +SortPointer implicitConstructorSort() +{ + return arity0FunctionSort(); +} + +SortPointer constructorSort(ContractDefinition const& _contract) +{ + if (auto const* constructor = _contract.constructor()) + return functionSort(*constructor, &_contract); + + return make_shared( + vector{SortProvider::uintSort} + stateSorts(_contract), + SortProvider::boolSort + ); +} + +SortPointer functionSort(FunctionDefinition const& _function, ContractDefinition const* _contract) +{ + auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }; + auto varSorts = _contract ? stateSorts(*_contract) : vector{}; + auto inputSorts = applyMap(_function.parameters(), smtSort); + auto outputSorts = applyMap(_function.returnParameters(), smtSort); + return make_shared( + vector{SortProvider::uintSort} + + varSorts + + inputSorts + + varSorts + + inputSorts + + outputSorts, + SortProvider::boolSort + ); +} + +SortPointer functionBodySort(FunctionDefinition const& _function, ContractDefinition const* _contract) +{ + auto fSort = dynamic_pointer_cast(functionSort(_function, _contract)); + solAssert(fSort, ""); + + auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }; + return make_shared( + fSort->domain + applyMap(_function.localVariables(), smtSort), + SortProvider::boolSort + ); +} + +SortPointer arity0FunctionSort() +{ + return make_shared( + vector(), + SortProvider::boolSort + ); +} + +/// Helpers + +vector stateSorts(ContractDefinition const& _contract) +{ + return applyMap( + SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract), + [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); } + ); +} + +} diff --git a/libsolidity/formal/PredicateSort.h b/libsolidity/formal/PredicateSort.h new file mode 100644 index 000000000..04d5226c6 --- /dev/null +++ b/libsolidity/formal/PredicateSort.h @@ -0,0 +1,82 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +#include + +namespace solidity::frontend::smt +{ + +/** + * This file represents the specification for CHC predicate sorts. + * Types of predicates: + * + * 1. Interface + * The idle state of a contract. Signature: + * interface(stateVariables). + * + * 2. Nondet interface + * The nondeterminism behavior of a contract. Signature: + * nondet_interface(stateVariables, stateVariables'). + * + * 3. Implicit constructor + * The implicit constructor of a contract, that is, without input parameters. Signature: + * implicit_constructor(). + * + * 4. Constructor entry/summary + * The summary of an implicit constructor. Signature: + * constructor_summary(error, stateVariables'). + * + * 5. Function entry/summary + * The entry point of a function definition. Signature: + * function_entry(error, stateVariables, inputVariables, stateVariables', inputVariables', outputVariables'). + * + * 6. Function body + * Use for any predicate within a function. Signature: + * function_body(error, stateVariables, inputVariables, stateVariables', inputVariables', outputVariables', localVariables). + */ + +/// @returns the interface predicate sort for _contract. +smtutil::SortPointer interfaceSort(ContractDefinition const& _contract); + +/// @returns the nondeterminisc interface predicate sort for _contract. +smtutil::SortPointer nondetInterfaceSort(ContractDefinition const& _contract); + +/// @returns the implicit constructor predicate sort. +smtutil::SortPointer implicitConstructorSort(); + +/// @returns the constructor entry/summary predicate sort for _contract. +smtutil::SortPointer constructorSort(ContractDefinition const& _contract); + +/// @returns the function entry/summary predicate sort for _function contained in _contract. +smtutil::SortPointer functionSort(FunctionDefinition const& _function, ContractDefinition const* _contract); + +/// @returns the function body predicate sort for _function contained in _contract. +smtutil::SortPointer functionBodySort(FunctionDefinition const& _function, ContractDefinition const* _contract); + +/// @returns the sort of a predicate without parameters. +smtutil::SortPointer arity0FunctionSort(); + +/// Helpers + +std::vector stateSorts(ContractDefinition const& _contract) ; + +} diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 644e9200e..fd599e3db 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -133,10 +134,7 @@ bool SMTEncoder::visit(FunctionDefinition const& _function) if (_function.isConstructor()) inlineConstructorHierarchy(dynamic_cast(*_function.scope())); - // Base constructors' parameters should be set by explicit calls, - // but the most derived one needs to be initialized. - if (_function.scope() == m_currentContract) - initializeLocalVariables(_function); + initializeLocalVariables(_function); _function.parameterList().accept(*this); if (_function.returnParameterList()) @@ -354,31 +352,10 @@ void SMTEncoder::endVisit(Assignment const& _assignment) { createExpr(_assignment); - static set const compoundOps{ - Token::AssignAdd, - Token::AssignSub, - Token::AssignMul, - Token::AssignDiv, - Token::AssignMod - }; Token op = _assignment.assignmentOperator(); - if (op != Token::Assign && !compoundOps.count(op)) - { - Expression const* identifier = &_assignment.leftHandSide(); - if (auto const* indexAccess = dynamic_cast(identifier)) - identifier = leftmostBase(*indexAccess); - // Give it a new index anyway to keep the SSA scheme sound. - solAssert(identifier, ""); - if (auto varDecl = identifierToVariable(*identifier)) - m_context.newValue(*varDecl); + solAssert(TokenTraits::isAssignmentOp(op), ""); - m_errorReporter.warning( - 9149_error, - _assignment.location(), - "Assertion checker does not yet implement this assignment operator." - ); - } - else if (!smt::isSupportedType(_assignment.annotation().type->category())) + if (!smt::isSupportedType(*_assignment.annotation().type)) { // Give it a new index anyway to keep the SSA scheme sound. @@ -396,15 +373,14 @@ void SMTEncoder::endVisit(Assignment const& _assignment) else { auto const& type = _assignment.annotation().type; - auto rightHandSide = compoundOps.count(op) ? - compoundAssignment(_assignment) : - expr(_assignment.rightHandSide(), type); + auto rightHandSide = op == Token::Assign ? + expr(_assignment.rightHandSide(), type) : + compoundAssignment(_assignment); defineExpr(_assignment, rightHandSide); assignment( _assignment.leftHandSide(), expr(_assignment, type), - type, - _assignment.location() + type ); } } @@ -463,20 +439,19 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) createExpr(_op); auto const* subExpr = innermostTuple(_op.subExpression()); - + auto type = _op.annotation().type; switch (_op.getOperator()) { case Token::Not: // ! { - solAssert(smt::isBool(_op.annotation().type->category()), ""); + solAssert(smt::isBool(*type), ""); defineExpr(_op, !expr(*subExpr)); break; } case Token::Inc: // ++ (pre- or postfix) case Token::Dec: // -- (pre- or postfix) { - auto cat = _op.annotation().type->category(); - solAssert(smt::isInteger(cat) || smt::isFixedPoint(cat), ""); + solAssert(smt::isInteger(*type) || smt::isFixedPoint(*type), ""); solAssert(subExpr->annotation().willBeWrittenTo, ""); if (auto identifier = dynamic_cast(subExpr)) { @@ -487,12 +462,15 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) defineExpr(_op, _op.isPrefixOperation() ? newValue : innerValue); assignment(*decl, newValue); } - else if (dynamic_cast(subExpr)) + else if ( + dynamic_cast(&_op.subExpression()) || + dynamic_cast(&_op.subExpression()) + ) { auto innerValue = expr(*subExpr); auto newValue = _op.getOperator() == Token::Inc ? innerValue + 1 : innerValue - 1; defineExpr(_op, _op.isPrefixOperation() ? newValue : innerValue); - arrayIndexAssignment(*subExpr, newValue); + indexOrMemberAssignment(_op.subExpression(), newValue); } else m_errorReporter.warning( @@ -521,14 +499,13 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) auto const& symbVar = m_context.expression(*subExpr); symbVar->increaseIndex(); m_context.setZeroValue(*symbVar); - if (dynamic_cast(subExpr)) - arrayIndexAssignment(*subExpr, symbVar->currentValue()); + if ( + dynamic_cast(&_op.subExpression()) || + dynamic_cast(&_op.subExpression()) + ) + indexOrMemberAssignment(_op.subExpression(), symbVar->currentValue()); else - m_errorReporter.warning( - 2683_error, - _op.location(), - "Assertion checker does not yet implement \"delete\" for this expression." - ); + solAssert(false, ""); } break; } @@ -571,7 +548,7 @@ void SMTEncoder::endVisit(BinaryOperation const& _op) arithmeticOperation(_op); else if (TokenTraits::isCompareOp(_op.getOperator())) compareOperation(_op); - else if (TokenTraits::isBitOp(_op.getOperator())) + else if (TokenTraits::isBitOp(_op.getOperator()) || TokenTraits::isShiftOp(_op.getOperator())) bitwiseOperation(_op); else m_errorReporter.warning( @@ -634,6 +611,10 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) case FunctionType::Kind::Require: visitRequire(_funCall); break; + case FunctionType::Kind::Revert: + // Revert is a special case of require and equals to `require(false)` + addPathImpliedExpression(smtutil::Expression(false)); + break; case FunctionType::Kind::GasLeft: visitGasLeft(_funCall); break; @@ -674,6 +655,17 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) case FunctionType::Kind::ArrayPop: arrayPop(_funCall); break; + case FunctionType::Kind::Log0: + case FunctionType::Kind::Log1: + case FunctionType::Kind::Log2: + case FunctionType::Kind::Log3: + case FunctionType::Kind::Log4: + case FunctionType::Kind::Event: + // These can be safely ignored. + break; + case FunctionType::Kind::ObjectCreation: + visitObjectCreation(_funCall); + return; default: m_errorReporter.warning( 4588_error, @@ -746,6 +738,25 @@ void SMTEncoder::visitGasLeft(FunctionCall const& _funCall) m_context.addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1)); } +void SMTEncoder::visitObjectCreation(FunctionCall const& _funCall) +{ + auto const& args = _funCall.arguments(); + solAssert(args.size() >= 1, ""); + auto argType = args.front()->annotation().type->category(); + solAssert(argType == Type::Category::Integer || argType == Type::Category::RationalNumber, ""); + + smtutil::Expression arraySize = expr(*args.front()); + setSymbolicUnknownValue(arraySize, TypeProvider::uint256(), m_context); + + auto symbArray = dynamic_pointer_cast(m_context.expression(_funCall)); + solAssert(symbArray, ""); + smt::setSymbolicZeroValue(*symbArray, m_context); + auto zeroElements = symbArray->elements(); + symbArray->increaseIndex(); + m_context.addAssertion(symbArray->length() == arraySize); + m_context.addAssertion(symbArray->elements() == zeroElements); +} + void SMTEncoder::endVisit(Identifier const& _identifier) { if (auto decl = identifierToVariable(_identifier)) @@ -759,6 +770,13 @@ void SMTEncoder::endVisit(Identifier const& _identifier) defineExpr(_identifier, m_context.state().thisAddress()); m_uninterpretedTerms.insert(&_identifier); } + // Ignore the builtin abi, it is handled in FunctionCall. + // TODO: ignore MagicType in general (abi, block, msg, tx, type) + else if (auto magicType = dynamic_cast(_identifier.annotation().type); magicType && magicType->kind() == MagicType::Kind::ABI) + { + solAssert(_identifier.name() == "abi", ""); + return; + } else createExpr(_identifier); } @@ -782,12 +800,19 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall) auto argument = _funCall.arguments().front(); unsigned argSize = argument->annotation().type->storageBytes(); unsigned castSize = _funCall.annotation().type->storageBytes(); - if (argSize == castSize) + auto const& funCallCategory = _funCall.annotation().type->category(); + // Allow casting number literals to address. + // TODO: remove the isNegative() check once the type checker disallows this + if ( + auto const* numberType = dynamic_cast(argument->annotation().type); + numberType && !numberType->isNegative() && (funCallCategory == Type::Category::Address) + ) + defineExpr(_funCall, numberType->literalValue(nullptr)); + else if (argSize == castSize) defineExpr(_funCall, expr(*argument)); else { m_context.setUnknownValue(*m_context.expression(_funCall)); - auto const& funCallCategory = _funCall.annotation().type->category(); // TODO: truncating and bytesX needs a different approach because of right padding. if (funCallCategory == Type::Category::Integer || funCallCategory == Type::Category::Address) { @@ -826,12 +851,25 @@ void SMTEncoder::endVisit(Literal const& _literal) { solAssert(_literal.annotation().type, "Expected type for AST node"); Type const& type = *_literal.annotation().type; - if (smt::isNumber(type.category())) + if (smt::isNumber(type)) defineExpr(_literal, smtutil::Expression(type.literalValue(&_literal))); - else if (smt::isBool(type.category())) + else if (smt::isBool(type)) defineExpr(_literal, smtutil::Expression(_literal.token() == Token::TrueLiteral ? true : false)); - else if (smt::isStringLiteral(type.category())) + else if (smt::isStringLiteral(type)) + { createExpr(_literal); + + // Add constraints for the length and values as it is known. + auto symbArray = dynamic_pointer_cast(m_context.expression(_literal)); + solAssert(symbArray, ""); + + auto value = _literal.value(); + m_context.addAssertion(symbArray->length() == value.length()); + for (size_t i = 0; i < value.length(); i++) + m_context.addAssertion( + smtutil::Expression::select(symbArray->elements(), i) == size_t(value[i]) + ); + } else { m_errorReporter.warning( @@ -881,16 +919,43 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) auto identifier = dynamic_cast(&_memberAccess.expression()); if (exprType->category() == Type::Category::Magic) { - string accessedName; if (identifier) - accessedName = identifier->name(); + defineGlobalVariable(identifier->name() + "." + _memberAccess.memberName(), _memberAccess); + else if (auto magicType = dynamic_cast(exprType); magicType->kind() == MagicType::Kind::MetaType) + { + auto const& memberName = _memberAccess.memberName(); + if (memberName == "min" || memberName == "max") + { + IntegerType const& integerType = dynamic_cast(*magicType->typeArgument()); + defineExpr(_memberAccess, memberName == "min" ? integerType.minValue() : integerType.maxValue()); + } + else if (memberName == "interfaceId") + { + ContractDefinition const& contract = dynamic_cast(*magicType->typeArgument()).contractDefinition(); + defineExpr(_memberAccess, contract.interfaceId()); + } + else + // NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not + // at all useable in the SMT checker currently + m_errorReporter.warning( + 7507_error, + _memberAccess.location(), + "Assertion checker does not yet support this expression." + ); + } else m_errorReporter.warning( 9551_error, _memberAccess.location(), "Assertion checker does not yet support this expression." ); - defineGlobalVariable(accessedName + "." + _memberAccess.memberName(), _memberAccess); + return false; + } + else if (smt::isNonRecursiveStruct(*exprType)) + { + _memberAccess.expression().accept(*this); + auto const& symbStruct = dynamic_pointer_cast(m_context.expression(_memberAccess.expression())); + defineExpr(_memberAccess, symbStruct->member(_memberAccess.memberName())); return false; } else if (exprType->category() == Type::Category::TypeType) @@ -947,13 +1012,36 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess) if (_indexAccess.annotation().type->category() == Type::Category::TypeType) return; - if (_indexAccess.baseExpression().annotation().type->category() == Type::Category::FixedBytes) + if (auto const* type = dynamic_cast(_indexAccess.baseExpression().annotation().type)) { - m_errorReporter.warning( - 7989_error, - _indexAccess.location(), - "Assertion checker does not yet support index accessing fixed bytes." - ); + smtutil::Expression base = expr(_indexAccess.baseExpression()); + + if (type->numBytes() == 1) + defineExpr(_indexAccess, base); + else + { + auto [bvSize, isSigned] = smt::typeBvSizeAndSignedness(_indexAccess.baseExpression().annotation().type); + solAssert(!isSigned, ""); + solAssert(bvSize >= 16, ""); + solAssert(bvSize % 8 == 0, ""); + + smtutil::Expression idx = expr(*_indexAccess.indexExpression()); + + auto bvBase = smtutil::Expression::int2bv(base, bvSize); + auto bvShl = smtutil::Expression::int2bv(idx * 8, bvSize); + auto bvShr = smtutil::Expression::int2bv(bvSize - 8, bvSize); + auto result = (bvBase << bvShl) >> bvShr; + + auto anyValue = expr(_indexAccess); + m_context.expression(_indexAccess)->increaseIndex(); + unsigned numBytes = bvSize / 8; + auto withBound = smtutil::Expression::ite( + idx < numBytes, + smtutil::Expression::bv2int(result, false), + anyValue + ); + defineExpr(_indexAccess, withBound); + } return; } @@ -964,19 +1052,10 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess) solAssert(varDecl, ""); array = m_context.variable(*varDecl); } - else if (auto const* innerAccess = dynamic_cast(&_indexAccess.baseExpression())) - { - solAssert(m_context.knownExpression(*innerAccess), ""); - array = m_context.expression(*innerAccess); - } else { - m_errorReporter.warning( - 9118_error, - _indexAccess.location(), - "Assertion checker does not yet implement this expression." - ); - return; + solAssert(m_context.knownExpression(_indexAccess.baseExpression()), ""); + array = m_context.expression(_indexAccess.baseExpression()); } auto arrayVar = dynamic_pointer_cast(array); @@ -1008,14 +1087,58 @@ void SMTEncoder::arrayAssignment() m_arrayAssignmentHappened = true; } -void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smtutil::Expression const& _rightHandSide) +void SMTEncoder::indexOrMemberAssignment(Expression const& _expr, smtutil::Expression const& _rightHandSide) { auto toStore = _rightHandSide; - auto indexAccess = dynamic_cast(&_expr); - solAssert(indexAccess, ""); + auto const* lastExpr = &_expr; while (true) { - if (auto const& id = dynamic_cast(&indexAccess->baseExpression())) + if (auto const* indexAccess = dynamic_cast(lastExpr)) + { + auto const& base = indexAccess->baseExpression(); + if (dynamic_cast(&base)) + base.accept(*this); + auto symbArray = dynamic_pointer_cast(m_context.expression(base)); + solAssert(symbArray, ""); + auto baseType = symbArray->type(); + toStore = smtutil::Expression::tuple_constructor( + smtutil::Expression(make_shared(smt::smtSort(*baseType)), baseType->toString(true)), + {smtutil::Expression::store(symbArray->elements(), expr(*indexAccess->indexExpression()), toStore), symbArray->length()} + ); + m_context.expression(*indexAccess)->increaseIndex(); + defineExpr(*indexAccess, smtutil::Expression::select( + symbArray->elements(), + expr(*indexAccess->indexExpression()) + )); + lastExpr = &indexAccess->baseExpression(); + } + else if (auto const* memberAccess = dynamic_cast(lastExpr)) + { + auto const& base = memberAccess->expression(); + if (dynamic_cast(&base)) + base.accept(*this); + + if ( + auto const* structType = dynamic_cast(base.annotation().type); + structType && structType->recursive() + ) + { + m_errorReporter.warning( + 4375_error, + memberAccess->location(), + "Assertion checker does not support recursive structs." + ); + return; + } + + auto symbStruct = dynamic_pointer_cast(m_context.expression(base)); + solAssert(symbStruct, ""); + symbStruct->assignMember(memberAccess->memberName(), toStore); + toStore = symbStruct->currentValue(); + defineExpr(*memberAccess, symbStruct->member(memberAccess->memberName())); + lastExpr = &memberAccess->expression(); + } + else if (auto const& id = dynamic_cast(lastExpr)) { auto varDecl = identifierToVariable(*id); solAssert(varDecl, ""); @@ -1023,43 +1146,22 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smtutil::Expressi if (varDecl->hasReferenceOrMappingType()) resetReferences(*varDecl); - auto symbArray = dynamic_pointer_cast(m_context.variable(*varDecl)); - smtutil::Expression store = smtutil::Expression::store( - symbArray->elements(), - expr(*indexAccess->indexExpression()), - toStore - ); - auto oldLength = symbArray->length(); - symbArray->increaseIndex(); - m_context.addAssertion(symbArray->elements() == store); - m_context.addAssertion(symbArray->length() == oldLength); - // Update the SMT select value after the assignment, - // necessary for sound models. - defineExpr(*indexAccess, smtutil::Expression::select( - symbArray->elements(), - expr(*indexAccess->indexExpression()) - )); - + m_context.addAssertion(m_context.newValue(*varDecl) == toStore); + m_context.expression(*id)->increaseIndex(); + defineExpr(*id,currentValue(*varDecl)); break; } - else if (auto base = dynamic_cast(&indexAccess->baseExpression())) - { - auto symbArray = dynamic_pointer_cast(m_context.expression(*base)); - solAssert(symbArray, ""); - auto baseType = base->annotation().type; - toStore = smtutil::Expression::tuple_constructor( - smtutil::Expression(make_shared(smt::smtSort(*baseType)), baseType->toString(true)), - {smtutil::Expression::store(symbArray->elements(), expr(*indexAccess->indexExpression()), toStore), symbArray->length()} - ); - indexAccess = base; - } else { - m_errorReporter.warning( - 9056_error, - _expr.location(), - "Assertion checker does not yet implement this expression." - ); + auto type = lastExpr->annotation().type; + if ( + dynamic_cast(type) || + dynamic_cast(type) + ) + resetReferences(type); + + m_context.expression(*lastExpr)->increaseIndex(); + m_context.addAssertion(expr(*lastExpr) == toStore); break; } } @@ -1131,9 +1233,14 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression if (varDecl->hasReferenceOrMappingType()) resetReferences(*varDecl); m_context.addAssertion(m_context.newValue(*varDecl) == _array); + m_context.expression(*id)->increaseIndex(); + defineExpr(*id,currentValue(*varDecl)); } - else if (auto const* indexAccess = dynamic_cast(expr)) - arrayIndexAssignment(*indexAccess, _array); + else if ( + dynamic_cast(expr) || + dynamic_cast(expr) + ) + indexOrMemberAssignment(_expr, _array); else if (auto const* funCall = dynamic_cast(expr)) { FunctionType const& funType = dynamic_cast(*funCall->expression().annotation().type); @@ -1156,12 +1263,6 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression arrayPushPopAssign(memberAccess->expression(), symbArray->currentValue()); } } - else if (dynamic_cast(expr)) - m_errorReporter.warning( - 9599_error, - _expr.location(), - "Assertion checker does not yet implement this expression." - ); else solAssert(false, ""); } @@ -1182,7 +1283,7 @@ void SMTEncoder::defineGlobalVariable(string const& _name, Expression const& _ex m_context.globalSymbol(_name)->increaseIndex(); // The default behavior is not to increase the index since // most of the global values stay the same throughout a tx. - if (smt::isSupportedType(_expr.annotation().type->category())) + if (smt::isSupportedType(*_expr.annotation().type)) defineExpr(_expr, m_context.globalSymbol(_name)->currentValue()); } @@ -1331,17 +1432,70 @@ pair SMTEncoder::arithmeticOperation( return {value, valueUnbounded}; } +smtutil::Expression SMTEncoder::bitwiseOperation( + Token _op, + smtutil::Expression const& _left, + smtutil::Expression const& _right, + TypePointer const& _commonType +) +{ + static set validOperators{ + Token::BitAnd, + Token::BitOr, + Token::BitXor, + Token::SHL, + Token::SHR, + Token::SAR + }; + solAssert(validOperators.count(_op), ""); + solAssert(_commonType, ""); + + auto [bvSize, isSigned] = smt::typeBvSizeAndSignedness(_commonType); + + auto bvLeft = smtutil::Expression::int2bv(_left, bvSize); + auto bvRight = smtutil::Expression::int2bv(_right, bvSize); + + optional result; + switch (_op) + { + case Token::BitAnd: + result = bvLeft & bvRight; + break; + case Token::BitOr: + result = bvLeft | bvRight; + break; + case Token::BitXor: + result = bvLeft ^ bvRight; + break; + case Token::SHL: + result = bvLeft << bvRight; + break; + case Token::SHR: + solAssert(false, ""); + case Token::SAR: + result = isSigned ? + smtutil::Expression::ashr(bvLeft, bvRight) : + bvLeft >> bvRight; + break; + default: + solAssert(false, ""); + } + + solAssert(result.has_value(), ""); + return smtutil::Expression::bv2int(*result, isSigned); +} + void SMTEncoder::compareOperation(BinaryOperation const& _op) { auto const& commonType = _op.annotation().commonType; solAssert(commonType, ""); - if (smt::isSupportedType(commonType->category())) + if (smt::isSupportedType(*commonType)) { smtutil::Expression left(expr(_op.leftExpression(), commonType)); smtutil::Expression right(expr(_op.rightExpression(), commonType)); Token op = _op.getOperator(); shared_ptr value; - if (smt::isNumber(commonType->category())) + if (smt::isNumber(*commonType)) { value = make_shared( op == Token::Equal ? (left == right) : @@ -1354,7 +1508,7 @@ void SMTEncoder::compareOperation(BinaryOperation const& _op) } else // Bool { - solUnimplementedAssert(smt::isBool(commonType->category()), "Operation not yet supported"); + solUnimplementedAssert(smt::isBool(*commonType), "Operation not yet supported"); value = make_shared( op == Token::Equal ? (left == right) : /*op == Token::NotEqual*/ (left != right) @@ -1402,26 +1556,17 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op) void SMTEncoder::bitwiseOperation(BinaryOperation const& _op) { - solAssert(TokenTraits::isBitOp(_op.getOperator()), ""); + auto op = _op.getOperator(); + solAssert(TokenTraits::isBitOp(op) || TokenTraits::isShiftOp(op), ""); auto commonType = _op.annotation().commonType; solAssert(commonType, ""); - auto [bvSize, isSigned] = smt::typeBvSizeAndSignedness(commonType); - - auto bvLeft = smtutil::Expression::int2bv(expr(_op.leftExpression(), commonType), bvSize); - auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression(), commonType), bvSize); - - optional result; - if (_op.getOperator() == Token::BitAnd) - result = bvLeft & bvRight; - else if (_op.getOperator() == Token::BitOr) - result = bvLeft | bvRight; - else if (_op.getOperator() == Token::BitXor) - result = bvLeft ^ bvRight; - - solAssert(result, ""); - if (result) - defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned)); + defineExpr(_op, bitwiseOperation( + _op.getOperator(), + expr(_op.leftExpression(), commonType), + expr(_op.rightExpression(), commonType), + commonType + )); } void SMTEncoder::bitwiseNotOperation(UnaryOperation const& _op) @@ -1438,11 +1583,7 @@ smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Exp { // Signed division in SMTLIB2 rounds differently for negative division. if (_type.isSigned()) - return (smtutil::Expression::ite( - _left >= 0, - smtutil::Expression::ite(_right >= 0, _left / _right, 0 - (_left / (0 - _right))), - smtutil::Expression::ite(_right >= 0, 0 - ((0 - _left) / _right), (0 - _left) / (0 - _right)) - )); + return signedDivisionEVM(_left, _right); else return _left / _right; } @@ -1450,8 +1591,7 @@ smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Exp void SMTEncoder::assignment( Expression const& _left, smtutil::Expression const& _right, - TypePointer const& _type, - langutil::SourceLocation const& _location + TypePointer const& _type ) { solAssert( @@ -1461,28 +1601,21 @@ void SMTEncoder::assignment( Expression const* left = innermostTuple(_left); - if (!smt::isSupportedType(_type->category())) + if (!smt::isSupportedType(*_type)) { // Give it a new index anyway to keep the SSA scheme sound. if (auto varDecl = identifierToVariable(*left)) m_context.newValue(*varDecl); - - m_errorReporter.warning( - 6191_error, - _location, - "Assertion checker does not yet implement type " + _type->toString() - ); } else if (auto varDecl = identifierToVariable(*left)) assignment(*varDecl, _right); - else if (dynamic_cast(left)) - arrayIndexAssignment(*left, _right); + else if ( + dynamic_cast(left) || + dynamic_cast(left) + ) + indexOrMemberAssignment(*left, _right); else - m_errorReporter.warning( - 8182_error, - _location, - "Assertion checker does not yet implement such assignments." - ); + solAssert(false, ""); } void SMTEncoder::tupleAssignment(Expression const& _left, Expression const& _right) @@ -1511,7 +1644,7 @@ void SMTEncoder::tupleAssignment(Expression const& _left, Expression const& _rig else { auto type = lExpr.annotation().type; - assignment(lExpr, expr(rExpr, type), type, lExpr.location()); + assignment(lExpr, expr(rExpr, type), type); } } } @@ -1528,7 +1661,7 @@ void SMTEncoder::tupleAssignment(Expression const& _left, Expression const& _rig for (unsigned i = 0; i < lComponents.size(); ++i) if (auto component = lComponents.at(i); component && rComponents.at(i)) - assignment(*component, smtutil::Expression::tuple_get(symbRight, i), component->annotation().type, component->location()); + assignment(*component, smtutil::Expression::tuple_get(symbRight, i), component->annotation().type); } } @@ -1541,9 +1674,27 @@ smtutil::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment {Token::AssignDiv, Token::Div}, {Token::AssignMod, Token::Mod} }; + static map const compoundToBitwise{ + {Token::AssignBitAnd, Token::BitAnd}, + {Token::AssignBitOr, Token::BitOr}, + {Token::AssignBitXor, Token::BitXor}, + {Token::AssignShl, Token::SHL}, + {Token::AssignShr, Token::SHR}, + {Token::AssignSar, Token::SAR} + }; Token op = _assignment.assignmentOperator(); - solAssert(compoundToArithmetic.count(op), ""); + solAssert(compoundToArithmetic.count(op) || compoundToBitwise.count(op), ""); + auto decl = identifierToVariable(_assignment.leftHandSide()); + + if (compoundToBitwise.count(op)) + return bitwiseOperation( + compoundToBitwise.at(op), + decl ? currentValue(*decl) : expr(_assignment.leftHandSide()), + expr(_assignment.rightHandSide()), + _assignment.annotation().type + ); + auto values = arithmeticOperation( compoundToArithmetic.at(op), decl ? currentValue(*decl) : expr(_assignment.leftHandSide()), @@ -1561,9 +1712,7 @@ void SMTEncoder::assignment(VariableDeclaration const& _variable, Expression con // This is a special case where the SMT sorts are different. // For now we are unaware of other cases where this happens, but if they do appear // we should extract this into an `implicitConversion` function. - if (_variable.type()->category() != Type::Category::Array || _value.annotation().type->category() != Type::Category::StringLiteral) - assignment(_variable, expr(_value, _variable.type())); - // TODO else { store each string literal byte into the array } + assignment(_variable, expr(_value, _variable.type())); } void SMTEncoder::assignment(VariableDeclaration const& _variable, smtutil::Expression const& _value) @@ -1692,32 +1841,43 @@ void SMTEncoder::resetReferences(VariableDeclaration const& _varDecl) if (_var.isStateVariable() && _varDecl.isStateVariable()) return false; - TypePointer prefix = _var.type(); - TypePointer originalType = typeWithoutPointer(_varDecl.type()); - while ( - prefix->category() == Type::Category::Mapping || - prefix->category() == Type::Category::Array - ) - { - if (*originalType == *typeWithoutPointer(prefix)) - return true; - if (prefix->category() == Type::Category::Mapping) - { - auto mapPrefix = dynamic_cast(prefix); - solAssert(mapPrefix, ""); - prefix = mapPrefix->valueType(); - } - else - { - auto arrayPrefix = dynamic_cast(prefix); - solAssert(arrayPrefix, ""); - prefix = arrayPrefix->baseType(); - } - } - return false; + return sameTypeOrSubtype(_var.type(), _varDecl.type()); }); } +void SMTEncoder::resetReferences(TypePointer _type) +{ + m_context.resetVariables([&](VariableDeclaration const& _var) { + return sameTypeOrSubtype(_var.type(), _type); + }); +} + +bool SMTEncoder::sameTypeOrSubtype(TypePointer _a, TypePointer _b) +{ + TypePointer prefix = _a; + while ( + prefix->category() == Type::Category::Mapping || + prefix->category() == Type::Category::Array + ) + { + if (*typeWithoutPointer(_b) == *typeWithoutPointer(prefix)) + return true; + if (prefix->category() == Type::Category::Mapping) + { + auto mapPrefix = dynamic_cast(prefix); + solAssert(mapPrefix, ""); + prefix = mapPrefix->valueType(); + } + else + { + auto arrayPrefix = dynamic_cast(prefix); + solAssert(arrayPrefix, ""); + prefix = arrayPrefix->baseType(); + } + } + return false; +} + TypePointer SMTEncoder::typeWithoutPointer(TypePointer const& _type) { if (auto refType = dynamic_cast(_type)) @@ -1999,6 +2159,14 @@ vector SMTEncoder::stateVariablesIncludingInheritedA return stateVariablesIncludingInheritedAndPrivate(dynamic_cast(*_function.scope())); } +SourceUnit const* SMTEncoder::sourceUnitContaining(Scopable const& _scopable) +{ + for (auto const* s = &_scopable; s; s = dynamic_cast(s->scope())) + if (auto const* source = dynamic_cast(s->scope())) + return source; + solAssert(false, ""); +} + void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall) { FunctionDefinition const* funDef = functionCallToDefinition(_funCall); diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 6e7388155..adce5439b 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -65,6 +65,9 @@ public: static std::vector stateVariablesIncludingInheritedAndPrivate(ContractDefinition const& _contract); static std::vector stateVariablesIncludingInheritedAndPrivate(FunctionDefinition const& _function); + /// @returns the SourceUnit that contains _scopable. + static SourceUnit const* sourceUnitContaining(Scopable const& _scopable); + protected: // TODO: Check that we do not have concurrent reads and writes to a variable, // because the order of expression evaluation is undefined @@ -116,6 +119,14 @@ protected: TypePointer const& _commonType, Expression const& _expression ); + + smtutil::Expression bitwiseOperation( + Token _op, + smtutil::Expression const& _left, + smtutil::Expression const& _right, + TypePointer const& _commonType + ); + void compareOperation(BinaryOperation const& _op); void booleanOperation(BinaryOperation const& _op); void bitwiseOperation(BinaryOperation const& _op); @@ -126,6 +137,7 @@ protected: void visitAssert(FunctionCall const& _funCall); void visitRequire(FunctionCall const& _funCall); void visitGasLeft(FunctionCall const& _funCall); + void visitObjectCreation(FunctionCall const& _funCall); void visitTypeConversion(FunctionCall const& _funCall); void visitFunctionIdentifier(Identifier const& _identifier); @@ -146,8 +158,8 @@ protected: /// to variable of some SMT array type /// while aliasing is not supported. void arrayAssignment(); - /// Handles assignment to SMT array index. - void arrayIndexAssignment(Expression const& _expr, smtutil::Expression const& _rightHandSide); + /// Handles assignments to index or member access. + void indexOrMemberAssignment(Expression const& _expr, smtutil::Expression const& _rightHandSide); void arrayPush(FunctionCall const& _funCall); void arrayPop(FunctionCall const& _funCall); @@ -168,8 +180,7 @@ protected: void assignment( Expression const& _left, smtutil::Expression const& _right, - TypePointer const& _type, - langutil::SourceLocation const& _location + TypePointer const& _type ); /// Handle assignments between tuples. void tupleAssignment(Expression const& _left, Expression const& _right); @@ -196,8 +207,12 @@ protected: /// Resets all references/pointers that have the same type or have /// a subexpression of the same type as _varDecl. void resetReferences(VariableDeclaration const& _varDecl); + /// Resets all references/pointers that have type _type. + void resetReferences(TypePointer _type); /// @returns the type without storage pointer information if it has it. TypePointer typeWithoutPointer(TypePointer const& _type); + /// @returns whether _a or a subtype of _a is the same as _b. + bool sameTypeOrSubtype(TypePointer _a, TypePointer _b); /// Given two different branches and the touched variables, /// merge the touched variables into after-branch ite variables diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index 965130bb7..d363ea0e2 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -25,6 +25,7 @@ #include using namespace std; +using namespace solidity::util; using namespace solidity::smtutil; namespace solidity::frontend::smt @@ -32,7 +33,7 @@ namespace solidity::frontend::smt SortPointer smtSort(frontend::Type const& _type) { - switch (smtKind(_type.category())) + switch (smtKind(_type)) { case Kind::Int: if (auto const* intType = dynamic_cast(&_type)) @@ -63,13 +64,13 @@ SortPointer smtSort(frontend::Type const& _type) case Kind::Array: { shared_ptr array; - if (isMapping(_type.category())) + if (isMapping(_type)) { auto mapType = dynamic_cast(&_type); solAssert(mapType, ""); array = make_shared(smtSortAbstractFunction(*mapType->keyType()), smtSortAbstractFunction(*mapType->valueType())); } - else if (isStringLiteral(_type.category())) + else if (isStringLiteral(_type)) { auto stringLitType = dynamic_cast(&_type); solAssert(stringLitType, ""); @@ -130,18 +131,32 @@ SortPointer smtSort(frontend::Type const& _type) } case Kind::Tuple: { - auto tupleType = dynamic_cast(&_type); - solAssert(tupleType, ""); vector members; - auto const& tupleName = _type.identifier(); - auto const& components = tupleType->components(); - for (unsigned i = 0; i < components.size(); ++i) - members.emplace_back(tupleName + "_accessor_" + to_string(i)); - return make_shared( - tupleName, - members, - smtSortAbstractFunction(tupleType->components()) - ); + auto const& tupleName = _type.toString(true); + vector sorts; + + if (auto const* tupleType = dynamic_cast(&_type)) + { + auto const& components = tupleType->components(); + for (unsigned i = 0; i < components.size(); ++i) + members.emplace_back(tupleName + "_accessor_" + to_string(i)); + sorts = smtSortAbstractFunction(tupleType->components()); + } + else if (auto const* structType = dynamic_cast(&_type)) + { + solAssert(!structType->recursive(), ""); + auto const& structMembers = structType->structDefinition().members(); + for (auto member: structMembers) + members.emplace_back(tupleName + "_accessor_" + member->name()); + sorts = smtSortAbstractFunction(applyMap( + structMembers, + [](auto var) { return var->type(); } + )); + } + else + solAssert(false, ""); + + return make_shared(tupleName, members, sorts); } default: // Abstract case. @@ -159,7 +174,7 @@ vector smtSort(vector const& _types) SortPointer smtSortAbstractFunction(frontend::Type const& _type) { - if (isFunction(_type.category())) + if (isFunction(_type)) return SortProvider::uintSort; return smtSort(_type); } @@ -175,35 +190,36 @@ vector smtSortAbstractFunction(vector const& return sorts; } -Kind smtKind(frontend::Type::Category _category) +Kind smtKind(frontend::Type const& _type) { - if (isNumber(_category)) + if (isNumber(_type)) return Kind::Int; - else if (isBool(_category)) + else if (isBool(_type)) return Kind::Bool; - else if (isFunction(_category)) + else if (isFunction(_type)) return Kind::Function; - else if (isMapping(_category) || isArray(_category)) + else if (isMapping(_type) || isArray(_type)) return Kind::Array; - else if (isTuple(_category)) + else if (isTuple(_type) || isNonRecursiveStruct(_type)) return Kind::Tuple; // Abstract case. return Kind::Int; } -bool isSupportedType(frontend::Type::Category _category) +bool isSupportedType(frontend::Type const& _type) { - return isNumber(_category) || - isBool(_category) || - isMapping(_category) || - isArray(_category) || - isTuple(_category); + return isNumber(_type) || + isBool(_type) || + isMapping(_type) || + isArray(_type) || + isTuple(_type) || + isNonRecursiveStruct(_type); } -bool isSupportedTypeDeclaration(frontend::Type::Category _category) +bool isSupportedTypeDeclaration(frontend::Type const& _type) { - return isSupportedType(_category) || - isFunction(_category); + return isSupportedType(_type) || + isFunction(_type); } pair> newSymbolicVariable( @@ -220,9 +236,9 @@ pair> newSymbolicVariable( abstract = true; var = make_shared(frontend::TypeProvider::uint256(), type, _uniqueName, _context); } - else if (isBool(_type.category())) + else if (isBool(_type)) var = make_shared(type, _uniqueName, _context); - else if (isFunction(_type.category())) + else if (isFunction(_type)) { auto const& fType = dynamic_cast(type); auto const& paramsIn = fType->parameterTypes(); @@ -245,21 +261,21 @@ pair> newSymbolicVariable( else var = make_shared(type, _uniqueName, _context); } - else if (isInteger(_type.category())) + else if (isInteger(_type)) var = make_shared(type, type, _uniqueName, _context); - else if (isFixedPoint(_type.category())) + else if (isFixedPoint(_type)) var = make_shared(type, type, _uniqueName, _context); - else if (isFixedBytes(_type.category())) + else if (isFixedBytes(_type)) { auto fixedBytesType = dynamic_cast(type); solAssert(fixedBytesType, ""); var = make_shared(type, fixedBytesType->numBytes(), _uniqueName, _context); } - else if (isAddress(_type.category()) || isContract(_type.category())) + else if (isAddress(_type) || isContract(_type)) var = make_shared(_uniqueName, _context); - else if (isEnum(_type.category())) + else if (isEnum(_type)) var = make_shared(type, _uniqueName, _context); - else if (isRational(_type.category())) + else if (isRational(_type)) { auto rational = dynamic_cast(&_type); solAssert(rational, ""); @@ -268,106 +284,104 @@ pair> newSymbolicVariable( else var = make_shared(type, type, _uniqueName, _context); } - else if (isMapping(_type.category()) || isArray(_type.category())) + else if (isMapping(_type) || isArray(_type)) var = make_shared(type, type, _uniqueName, _context); - else if (isTuple(_type.category())) + else if (isTuple(_type)) var = make_shared(type, _uniqueName, _context); - else if (isStringLiteral(_type.category())) + else if (isStringLiteral(_type)) { auto stringType = TypeProvider::stringMemory(); var = make_shared(stringType, type, _uniqueName, _context); } + else if (isNonRecursiveStruct(_type)) + var = make_shared(type, _uniqueName, _context); else solAssert(false, ""); return make_pair(abstract, var); } -bool isSupportedType(frontend::Type const& _type) +bool isInteger(frontend::Type const& _type) { - return isSupportedType(_type.category()); + return _type.category() == frontend::Type::Category::Integer; } -bool isSupportedTypeDeclaration(frontend::Type const& _type) +bool isFixedPoint(frontend::Type const& _type) { - return isSupportedTypeDeclaration(_type.category()); + return _type.category() == frontend::Type::Category::FixedPoint; } -bool isInteger(frontend::Type::Category _category) +bool isRational(frontend::Type const& _type) { - return _category == frontend::Type::Category::Integer; + return _type.category() == frontend::Type::Category::RationalNumber; } -bool isFixedPoint(frontend::Type::Category _category) +bool isFixedBytes(frontend::Type const& _type) { - return _category == frontend::Type::Category::FixedPoint; + return _type.category() == frontend::Type::Category::FixedBytes; } -bool isRational(frontend::Type::Category _category) +bool isAddress(frontend::Type const& _type) { - return _category == frontend::Type::Category::RationalNumber; + return _type.category() == frontend::Type::Category::Address; } -bool isFixedBytes(frontend::Type::Category _category) +bool isContract(frontend::Type const& _type) { - return _category == frontend::Type::Category::FixedBytes; + return _type.category() == frontend::Type::Category::Contract; } -bool isAddress(frontend::Type::Category _category) +bool isEnum(frontend::Type const& _type) { - return _category == frontend::Type::Category::Address; + return _type.category() == frontend::Type::Category::Enum; } -bool isContract(frontend::Type::Category _category) +bool isNumber(frontend::Type const& _type) { - return _category == frontend::Type::Category::Contract; + return isInteger(_type) || + isFixedPoint(_type) || + isRational(_type) || + isFixedBytes(_type) || + isAddress(_type) || + isContract(_type) || + isEnum(_type); } -bool isEnum(frontend::Type::Category _category) +bool isBool(frontend::Type const& _type) { - return _category == frontend::Type::Category::Enum; + return _type.category() == frontend::Type::Category::Bool; } -bool isNumber(frontend::Type::Category _category) +bool isFunction(frontend::Type const& _type) { - return isInteger(_category) || - isFixedPoint(_category) || - isRational(_category) || - isFixedBytes(_category) || - isAddress(_category) || - isContract(_category) || - isEnum(_category); + return _type.category() == frontend::Type::Category::Function; } -bool isBool(frontend::Type::Category _category) +bool isMapping(frontend::Type const& _type) { - return _category == frontend::Type::Category::Bool; + return _type.category() == frontend::Type::Category::Mapping; } -bool isFunction(frontend::Type::Category _category) +bool isArray(frontend::Type const& _type) { - return _category == frontend::Type::Category::Function; + return _type.category() == frontend::Type::Category::Array || + _type.category() == frontend::Type::Category::StringLiteral || + _type.category() == frontend::Type::Category::ArraySlice; } -bool isMapping(frontend::Type::Category _category) +bool isTuple(frontend::Type const& _type) { - return _category == frontend::Type::Category::Mapping; + return _type.category() == frontend::Type::Category::Tuple; } -bool isArray(frontend::Type::Category _category) +bool isStringLiteral(frontend::Type const& _type) { - return _category == frontend::Type::Category::Array || - _category == frontend::Type::Category::StringLiteral || - _category == frontend::Type::Category::ArraySlice; + return _type.category() == frontend::Type::Category::StringLiteral; } -bool isTuple(frontend::Type::Category _category) +bool isNonRecursiveStruct(frontend::Type const& _type) { - return _category == frontend::Type::Category::Tuple; -} - -bool isStringLiteral(frontend::Type::Category _category) -{ - return _category == frontend::Type::Category::StringLiteral; + auto structType = dynamic_cast(&_type); + return structType && !structType->recursive(); } smtutil::Expression minValue(frontend::IntegerType const& _type) @@ -394,13 +408,13 @@ void setSymbolicZeroValue(smtutil::Expression _expr, frontend::TypePointer const smtutil::Expression zeroValue(frontend::TypePointer const& _type) { solAssert(_type, ""); - if (isSupportedType(_type->category())) + if (isSupportedType(*_type)) { - if (isNumber(_type->category())) + if (isNumber(*_type)) return 0; - if (isBool(_type->category())) + if (isBool(*_type)) return smtutil::Expression(false); - if (isArray(_type->category()) || isMapping(_type->category())) + if (isArray(*_type) || isMapping(*_type)) { auto tupleSort = dynamic_pointer_cast(smtSort(*_type)); solAssert(tupleSort, ""); @@ -421,11 +435,23 @@ smtutil::Expression zeroValue(frontend::TypePointer const& _type) solAssert(zeroArray, ""); return smtutil::Expression::tuple_constructor( - smtutil::Expression(std::make_shared(smtSort(*_type)), _type->toString(true)), + smtutil::Expression(std::make_shared(tupleSort), tupleSort->name), vector{*zeroArray, length} ); } + if (isNonRecursiveStruct(*_type)) + { + auto const* structType = dynamic_cast(_type); + auto structSort = dynamic_pointer_cast(smtSort(*_type)); + return smtutil::Expression::tuple_constructor( + smtutil::Expression(make_shared(structSort), structSort->name), + applyMap( + structType->structDefinition().members(), + [](auto var) { return zeroValue(var->type()); } + ) + ); + } solAssert(false, ""); } // Unsupported types are abstracted as Int. @@ -452,14 +478,14 @@ void setSymbolicUnknownValue(SymbolicVariable const& _variable, EncodingContext& void setSymbolicUnknownValue(smtutil::Expression _expr, frontend::TypePointer const& _type, EncodingContext& _context) { solAssert(_type, ""); - if (isEnum(_type->category())) + if (isEnum(*_type)) { auto enumType = dynamic_cast(_type); solAssert(enumType, ""); _context.addAssertion(_expr >= 0); _context.addAssertion(_expr < enumType->numberOfMembers()); } - else if (isInteger(_type->category())) + else if (isInteger(*_type)) { auto intType = dynamic_cast(_type); solAssert(intType, ""); diff --git a/libsolidity/formal/SymbolicTypes.h b/libsolidity/formal/SymbolicTypes.h index 8e08783d8..01bbe4d2c 100644 --- a/libsolidity/formal/SymbolicTypes.h +++ b/libsolidity/formal/SymbolicTypes.h @@ -34,29 +34,30 @@ std::vector smtSort(std::vector con smtutil::SortPointer smtSortAbstractFunction(frontend::Type const& _type); std::vector smtSortAbstractFunction(std::vector const& _types); /// Returns the SMT kind that models the Solidity type type category _category. -smtutil::Kind smtKind(frontend::Type::Category _category); +smtutil::Kind smtKind(frontend::Type const& _type); /// Returns true if type is fully supported (declaration and operations). -bool isSupportedType(frontend::Type::Category _category); +bool isSupportedType(frontend::Type const& _type); bool isSupportedType(frontend::Type const& _type); /// Returns true if type is partially supported (declaration). -bool isSupportedTypeDeclaration(frontend::Type::Category _category); +bool isSupportedTypeDeclaration(frontend::Type const& _type); bool isSupportedTypeDeclaration(frontend::Type const& _type); -bool isInteger(frontend::Type::Category _category); -bool isFixedPoint(frontend::Type::Category _category); -bool isRational(frontend::Type::Category _category); -bool isFixedBytes(frontend::Type::Category _category); -bool isAddress(frontend::Type::Category _category); -bool isContract(frontend::Type::Category _category); -bool isEnum(frontend::Type::Category _category); -bool isNumber(frontend::Type::Category _category); -bool isBool(frontend::Type::Category _category); -bool isFunction(frontend::Type::Category _category); -bool isMapping(frontend::Type::Category _category); -bool isArray(frontend::Type::Category _category); -bool isTuple(frontend::Type::Category _category); -bool isStringLiteral(frontend::Type::Category _category); +bool isInteger(frontend::Type const& _type); +bool isFixedPoint(frontend::Type const& _type); +bool isRational(frontend::Type const& _type); +bool isFixedBytes(frontend::Type const& _type); +bool isAddress(frontend::Type const& _type); +bool isContract(frontend::Type const& _type); +bool isEnum(frontend::Type const& _type); +bool isNumber(frontend::Type const& _type); +bool isBool(frontend::Type const& _type); +bool isFunction(frontend::Type const& _type); +bool isMapping(frontend::Type const& _type); +bool isArray(frontend::Type const& _type); +bool isTuple(frontend::Type const& _type); +bool isStringLiteral(frontend::Type const& _type); +bool isNonRecursiveStruct(frontend::Type const& _type); /// Returns a new symbolic variable, according to _type. /// Also returns whether the type is abstract or not, diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp index b09938e63..51711b383 100644 --- a/libsolidity/formal/SymbolicVariables.cpp +++ b/libsolidity/formal/SymbolicVariables.cpp @@ -21,8 +21,11 @@ #include #include +#include + using namespace std; using namespace solidity; +using namespace solidity::util; using namespace solidity::smtutil; using namespace solidity::frontend; using namespace solidity::frontend::smt; @@ -118,7 +121,7 @@ SymbolicIntVariable::SymbolicIntVariable( ): SymbolicVariable(_type, _originalType, move(_uniqueName), _context) { - solAssert(isNumber(m_type->category()), ""); + solAssert(isNumber(*m_type), ""); } SymbolicAddressVariable::SymbolicAddressVariable( @@ -218,7 +221,7 @@ SymbolicEnumVariable::SymbolicEnumVariable( ): SymbolicVariable(_type, _type, move(_uniqueName), _context) { - solAssert(isEnum(m_type->category()), ""); + solAssert(isEnum(*m_type), ""); } SymbolicTupleVariable::SymbolicTupleVariable( @@ -228,7 +231,7 @@ SymbolicTupleVariable::SymbolicTupleVariable( ): SymbolicVariable(_type, _type, move(_uniqueName), _context) { - solAssert(isTuple(m_type->category()), ""); + solAssert(isTuple(*m_type), ""); } SymbolicTupleVariable::SymbolicTupleVariable( @@ -274,7 +277,7 @@ SymbolicArrayVariable::SymbolicArrayVariable( m_context ) { - solAssert(isArray(m_type->category()) || isMapping(m_type->category()), ""); + solAssert(isArray(*m_type) || isMapping(*m_type), ""); } SymbolicArrayVariable::SymbolicArrayVariable( @@ -319,3 +322,47 @@ smtutil::Expression SymbolicArrayVariable::length() { return m_pair.component(1); } + +SymbolicStructVariable::SymbolicStructVariable( + frontend::TypePointer _type, + string _uniqueName, + EncodingContext& _context +): + SymbolicVariable(_type, _type, move(_uniqueName), _context) +{ + solAssert(isNonRecursiveStruct(*m_type), ""); + auto const* structType = dynamic_cast(_type); + solAssert(structType, ""); + auto const& members = structType->structDefinition().members(); + for (unsigned i = 0; i < members.size(); ++i) + { + solAssert(members.at(i), ""); + m_memberIndices.emplace(members.at(i)->name(), i); + } +} + +smtutil::Expression SymbolicStructVariable::member(string const& _member) +{ + return smtutil::Expression::tuple_get(currentValue(), m_memberIndices.at(_member)); +} + +smtutil::Expression SymbolicStructVariable::assignMember(string const& _member, smtutil::Expression const& _memberValue) +{ + auto const* structType = dynamic_cast(m_type); + solAssert(structType, ""); + auto const& structDef = structType->structDefinition(); + auto const& structMembers = structDef.members(); + auto oldMembers = applyMap( + structMembers, + [&](auto _member) { return member(_member->name()); } + ); + increaseIndex(); + for (unsigned i = 0; i < structMembers.size(); ++i) + { + auto const& memberName = structMembers.at(i)->name(); + auto newMember = memberName == _member ? _memberValue : oldMembers.at(i); + m_context.addAssertion(member(memberName) == newMember); + } + + return currentValue(); +} diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h index bdf36afd0..843043c9d 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -23,6 +23,8 @@ #include #include + +#include #include namespace solidity::frontend::smt @@ -265,4 +267,29 @@ private: SymbolicTupleVariable m_pair; }; +/** + * Specialization of SymbolicVariable for Struct. + */ +class SymbolicStructVariable: public SymbolicVariable +{ +public: + SymbolicStructVariable( + frontend::TypePointer _type, + std::string _uniqueName, + EncodingContext& _context + ); + + /// @returns the symbolic expression representing _member. + smtutil::Expression member(std::string const& _member); + + /// @returns the symbolic expression representing this struct + /// with field _member updated. + smtutil::Expression assignMember(std::string const& _member, smtutil::Expression const& _memberValue); + +private: + std::map m_memberIndices; +}; + + + } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 42acb75ec..b3fc18ad8 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,9 @@ #include #include +#include #include +#include #include #include @@ -297,6 +300,10 @@ bool CompilerStack::analyze() BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed.")); resolveImports(); + for (Source const* source: m_sourceOrder) + if (source->ast) + Scoper::assignScopes(*source->ast); + bool noErrors = true; try @@ -359,12 +366,10 @@ bool CompilerStack::analyze() // This also calculates whether a contract is abstract, which is needed by the // type checker. ContractLevelChecker contractLevelChecker(m_errorReporter); + for (Source const* source: m_sourceOrder) - if (source->ast) - for (ASTPointer const& node: source->ast->nodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - if (!contractLevelChecker.check(*contract)) - noErrors = false; + if (auto sourceAst = source->ast) + noErrors = contractLevelChecker.check(*sourceAst); // Requires ContractLevelChecker DocStringAnalyser docStringAnalyser(m_errorReporter); @@ -517,6 +522,10 @@ bool CompilerStack::compile() { if (m_generateEvmBytecode) compileContract(*contract, otherCompilers); + if (m_generateIR || m_generateEwasm) + generateIR(*contract); + if (m_generateEwasm) + generateEwasm(*contract); } catch (Error const& _error) { @@ -525,10 +534,28 @@ bool CompilerStack::compile() m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what()); return false; } - if (m_generateIR || m_generateEwasm) - generateIR(*contract); - if (m_generateEwasm) - generateEwasm(*contract); + catch (UnimplementedFeatureError const& _unimplementedError) + { + if ( + SourceLocation const* sourceLocation = + boost::get_error_info(_unimplementedError) + ) + { + string const* comment = _unimplementedError.comment(); + m_errorReporter.error( + 1834_error, + Error::Type::CodeGenerationError, + *sourceLocation, + "Unimplemented feature error" + + ((comment && !comment->empty()) ? ": " + *comment : string{}) + + " in " + + _unimplementedError.lineInfo() + ); + return false; + } + else + throw; + } } m_stackState = CompilationSuccessful; this->link(); @@ -586,6 +613,48 @@ evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _ return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr; } +Json::Value CompilerStack::generatedSources(string const& _contractName, bool _runtime) const +{ + if (m_stackState != CompilationSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + + Contract const& c = contract(_contractName); + util::LazyInit const& sources = + _runtime ? + c.runtimeGeneratedSources : + c.generatedSources; + return sources.init([&]{ + Json::Value sources{Json::arrayValue}; + // If there is no compiler, then no bytecode was generated and thus no + // sources were generated. + if (c.compiler) + { + string source = + _runtime ? + c.compiler->runtimeGeneratedYulUtilityCode() : + c.compiler->generatedYulUtilityCode(); + if (!source.empty()) + { + string sourceName = CompilerContext::yulUtilityFileName(); + unsigned sourceIndex = sourceIndices()[sourceName]; + ErrorList errors; + ErrorReporter errorReporter(errors); + auto scanner = make_shared(langutil::CharStream(source, sourceName)); + yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion); + shared_ptr parserResult = yul::Parser{errorReporter, dialect}.parse(scanner, false); + solAssert(parserResult, ""); + sources[0]["ast"] = yul::AsmJsonConverter{sourceIndex}(*parserResult); + sources[0]["name"] = sourceName; + sources[0]["id"] = sourceIndex; + sources[0]["language"] = "Yul"; + sources[0]["contents"] = move(source); + + } + } + return sources; + }); +} + string const* CompilerStack::sourceMapping(string const& _contractName) const { if (m_stackState != CompilationSuccessful) @@ -728,6 +797,8 @@ map CompilerStack::sourceIndices() const unsigned index = 0; for (auto const& s: m_sources) indices[s.first] = index++; + solAssert(!indices.count(CompilerContext::yulUtilityFileName()), ""); + indices[CompilerContext::yulUtilityFileName()] = index++; return indices; } @@ -1024,7 +1095,7 @@ void CompilerStack::resolveImports() for (ASTPointer const& node: _source->ast->nodes()) if (ImportDirective const* import = dynamic_cast(node.get())) { - string const& path = import->annotation().absolutePath; + string const& path = *import->annotation().absolutePath; solAssert(m_sources.count(path), ""); import->annotation().sourceUnit = m_sources[path].ast.get(); toposort(&m_sources[path]); @@ -1222,9 +1293,9 @@ string CompilerStack::createMetadata(Contract const& _contract) const /// All the source files (including self), which should be included in the metadata. set referencedSources; - referencedSources.insert(_contract.contract->sourceUnit().annotation().path); + referencedSources.insert(*_contract.contract->sourceUnit().annotation().path); for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true)) - referencedSources.insert(sourceUnit->annotation().path); + referencedSources.insert(*sourceUnit->annotation().path); meta["sources"] = Json::objectValue; for (auto const& s: m_sources) @@ -1290,7 +1361,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const meta["settings"]["evmVersion"] = m_evmVersion.name(); meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] = - _contract.contract->annotation().canonicalName; + *_contract.contract->annotation().canonicalName; meta["settings"]["remappings"] = Json::arrayValue; set remappings; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 1f4575913..8b048ad01 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -277,6 +277,10 @@ public: /// @returns runtime contract assembly items evmasm::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName) const; + /// @returns an array containing all utility sources generated during compilation. + /// Format: [ { name: string, id: number, language: "Yul", contents: string }, ... ] + Json::Value generatedSources(std::string const& _contractName, bool _runtime = false) const; + /// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr /// if the contract does not (yet) have bytecode. std::string const* sourceMapping(std::string const& _contractName) const; @@ -356,6 +360,8 @@ private: util::LazyInit storageLayout; util::LazyInit userDocumentation; util::LazyInit devDocumentation; + util::LazyInit generatedSources; + util::LazyInit runtimeGeneratedSources; mutable std::optional sourceMapping; mutable std::optional runtimeSourceMapping; }; diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index 67007fc4c..1a2095198 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -32,7 +32,7 @@ namespace solidity::frontend struct OptimiserSettings { static char constexpr DefaultYulOptimiserSteps[] = - "dhfoDgvulfnTUtnIf" // None of these can make stack problems worse + "NdhfoDgvulfnTUtnIf" // None of these can make stack problems worse "[" "xarrscLM" // Turn into SSA and simplify "cCTUtTOntnfDIul" // Perform structural simplification @@ -41,13 +41,13 @@ struct OptimiserSettings // should have good "compilability" property here. - "eul" // Run functional expression inliner + "Tpeul" // Run functional expression inliner "xarulrul" // Prune a bit more in SSA "xarrcL" // Turn into SSA again and simplify "gvif" // Run full inliner "CTUcarrLsTOtfDncarrIulc" // SSA plus simplify "]" - "jmuljuljul VcTOcul jmul"; // Make source short and pretty + "jmuljuljul VcTOcul jmulN"; // Make source short and pretty /// No optimisations at all - not recommended. static OptimiserSettings none() diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 4506a6f7e..f708c5a4a 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -230,6 +230,16 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil return false; } +/// @returns all artifact names of the EVM object, either for creation or deploy time. +vector evmObjectComponents(string const& _objectKind) +{ + solAssert(_objectKind == "bytecode" || _objectKind == "deployedBytecode", ""); + vector components{"", ".object", ".opcodes", ".sourceMap", ".generatedSources", ".linkReferences"}; + if (_objectKind == "deployedBytecode") + components.push_back(".immutableReferences"); + return util::applyMap(components, [&](auto const& _s) { return "evm." + _objectKind + _s; }); +} + /// @returns true if any binary was requested, i.e. we actually have to perform compilation. bool isBinaryRequested(Json::Value const& _outputSelection) { @@ -237,17 +247,12 @@ bool isBinaryRequested(Json::Value const& _outputSelection) return false; // This does not include "evm.methodIdentifiers" on purpose! - static vector const outputsThatRequireBinaries{ + static vector const outputsThatRequireBinaries = vector{ "*", "ir", "irOptimized", "wast", "wasm", "ewasm.wast", "ewasm.wasm", - "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", - "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", - "evm.deployedBytecode.immutableReferences", - "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", - "evm.bytecode.linkReferences", "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly" - }; + } + evmObjectComponents("bytecode") + evmObjectComponents("deployedBytecode"); for (auto const& fileRequests: _outputSelection) for (auto const& requests: fileRequests) @@ -263,15 +268,10 @@ bool isEvmBytecodeRequested(Json::Value const& _outputSelection) if (!_outputSelection.isObject()) return false; - static vector const outputsThatRequireEvmBinaries{ + static vector const outputsThatRequireEvmBinaries = vector{ "*", - "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", - "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", - "evm.deployedBytecode.immutableReferences", - "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", - "evm.bytecode.linkReferences", "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly" - }; + } + evmObjectComponents("bytecode") + evmObjectComponents("deployedBytecode"); for (auto const& fileRequests: _outputSelection) for (auto const& requests: fileRequests) @@ -364,7 +364,12 @@ Json::Value formatImmutableReferences(map>> co return ret; } -Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* _sourceMap, bool _runtimeObject) +Json::Value collectEVMObject( + evmasm::LinkerObject const& _object, + string const* _sourceMap, + Json::Value _generatedSources, + bool _runtimeObject +) { Json::Value output = Json::objectValue; output["object"] = _object.toHex(); @@ -373,6 +378,7 @@ Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* output["linkReferences"] = formatLinkReferences(_object.linkReferences); if (_runtimeObject) output["immutableReferences"] = formatImmutableReferences(_object.immutableReferences); + output["generatedSources"] = move(_generatedSources); return output; } @@ -1074,12 +1080,13 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting _inputsAndSettings.outputSelection, file, name, - { "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" }, + evmObjectComponents("bytecode"), wildcardMatchesExperimental )) evmData["bytecode"] = collectEVMObject( compilerStack.object(contractName), compilerStack.sourceMapping(contractName), + compilerStack.generatedSources(contractName), false ); @@ -1087,12 +1094,13 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting _inputsAndSettings.outputSelection, file, name, - { "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", "evm.deployedBytecode.immutableReferences" }, + evmObjectComponents("deployedBytecode"), wildcardMatchesExperimental )) evmData["deployedBytecode"] = collectEVMObject( compilerStack.runtimeObject(contractName), compilerStack.runtimeSourceMapping(contractName), + compilerStack.generatedSources(contractName, true), true ); @@ -1176,24 +1184,19 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) tie(object, runtimeObject) = stack.assembleAndGuessRuntime(); for (string const& objectKind: vector{"bytecode", "deployedBytecode"}) - { - auto artifacts = util::applyMap( - vector{"", ".object", ".opcodes", ".sourceMap", ".linkReferences"}, - [&](auto const& _s) { return "evm." + objectKind + _s; } - ); if (isArtifactRequested( _inputsAndSettings.outputSelection, sourceName, contractName, - artifacts, + evmObjectComponents(objectKind), wildcardMatchesExperimental )) { MachineAssemblyObject const& o = objectKind == "bytecode" ? object : runtimeObject; if (o.bytecode) - output["contracts"][sourceName][contractName]["evm"][objectKind] = collectEVMObject(*o.bytecode, o.sourceMappings.get(), false); + output["contracts"][sourceName][contractName]["evm"][objectKind] = + collectEVMObject(*o.bytecode, o.sourceMappings.get(), Json::arrayValue, false); } - } if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized", wildcardMatchesExperimental)) output["contracts"][sourceName][contractName]["irOptimized"] = stack.print(); diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index b01e24c38..4ab824791 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -209,6 +209,13 @@ std::map invertMap(std::map const& originalMap) return inverseMap; } +/// Returns a set of keys of a map. +template +std::set keys(std::map const& _map) +{ + return applyMap(_map, [](auto const& _elem) { return _elem.first; }, std::set{}); +} + // String conversion functions, mainly to/from hex/nibble/byte representations. enum class WhenError diff --git a/libsolutil/SetOnce.h b/libsolutil/SetOnce.h index 289258e7b..007424ff1 100644 --- a/libsolutil/SetOnce.h +++ b/libsolutil/SetOnce.h @@ -79,6 +79,8 @@ public: /// @throws BadSetOnceAccess when the stored value has not yet been set T const* operator->() const { return std::addressof(**this); } + /// @return true if a value was assigned + bool set() const { return m_value.has_value(); } private: std::optional m_value = std::nullopt; }; diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 65269e9e0..a6d41bb07 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -105,6 +105,8 @@ add_library(yul optimiser/ForLoopInitRewriter.h optimiser/FullInliner.cpp optimiser/FullInliner.h + optimiser/FunctionCallFinder.cpp + optimiser/FunctionCallFinder.h optimiser/FunctionGrouper.cpp optimiser/FunctionGrouper.h optimiser/FunctionHoister.cpp @@ -127,9 +129,13 @@ add_library(yul optimiser/NameDispenser.h optimiser/NameDisplacer.cpp optimiser/NameDisplacer.h + optimiser/NameSimplifier.cpp + optimiser/NameSimplifier.h optimiser/OptimiserStep.h optimiser/OptimizerUtilities.cpp optimiser/OptimizerUtilities.h + optimiser/ReasoningBasedSimplifier.cpp + optimiser/ReasoningBasedSimplifier.h optimiser/RedundantAssignEliminator.cpp optimiser/RedundantAssignEliminator.h optimiser/Rematerialiser.cpp @@ -146,6 +152,10 @@ add_library(yul optimiser/SimplificationRules.h optimiser/StackCompressor.cpp optimiser/StackCompressor.h + optimiser/StackLimitEvader.cpp + optimiser/StackLimitEvader.h + optimiser/StackToMemoryMover.cpp + optimiser/StackToMemoryMover.h optimiser/StructuralSimplifier.cpp optimiser/StructuralSimplifier.h optimiser/Substitution.cpp @@ -156,6 +166,9 @@ add_library(yul optimiser/SyntacticalEquality.h optimiser/TypeInfo.cpp optimiser/TypeInfo.h + optimiser/UnusedFunctionParameterPruner.cpp + optimiser/UnusedFunctionParameterPruner.h + optimiser/UnusedFunctionsCommon.h optimiser/UnusedPruner.cpp optimiser/UnusedPruner.h optimiser/VarDeclInitializer.cpp @@ -163,4 +176,5 @@ add_library(yul optimiser/VarNameCleaner.cpp optimiser/VarNameCleaner.h ) -target_link_libraries(yul PUBLIC evmasm solutil langutil) + +target_link_libraries(yul PUBLIC evmasm solutil langutil smtutil) \ No newline at end of file diff --git a/libyul/CompilabilityChecker.cpp b/libyul/CompilabilityChecker.cpp index 2a99e3c79..4b1a99a74 100644 --- a/libyul/CompilabilityChecker.cpp +++ b/libyul/CompilabilityChecker.cpp @@ -33,7 +33,7 @@ using namespace solidity; using namespace solidity::yul; using namespace solidity::util; -map CompilabilityChecker::run( +CompilabilityChecker::CompilabilityChecker( Dialect const& _dialect, Object const& _object, bool _optimizeStackAllocation @@ -63,12 +63,11 @@ map CompilabilityChecker::run( ); transform(*_object.code); - std::map functions; for (StackTooDeepError const& error: transform.stackErrors()) - functions[error.functionName] = max(error.depth, functions[error.functionName]); - - return functions; + { + unreachableVariables[error.functionName].emplace(error.variable); + int& deficit = stackDeficit[error.functionName]; + deficit = std::max(error.depth, deficit); + } } - else - return {}; } diff --git a/libyul/CompilabilityChecker.h b/libyul/CompilabilityChecker.h index 1267640bf..ba9191e28 100644 --- a/libyul/CompilabilityChecker.h +++ b/libyul/CompilabilityChecker.h @@ -33,22 +33,20 @@ namespace solidity::yul /** * Component that checks whether all variables are reachable on the stack and - * returns a mapping from function name to the largest stack difference found - * in that function (no entry present if that function is compilable). + * provides a mapping from function name to the largest stack difference found + * in that function (no entry present if that function is compilable), as well + * as the set of unreachable variables for each function. * * This only works properly if the outermost block is compilable and * functions are not nested. Otherwise, it might miss reporting some functions. * * Only checks the code of the object itself, does not descend into sub-objects. */ -class CompilabilityChecker +struct CompilabilityChecker { -public: - static std::map run( - Dialect const& _dialect, - Object const& _object, - bool _optimizeStackAllocation - ); + CompilabilityChecker(Dialect const& _dialect, Object const& _object, bool _optimizeStackAllocation); + std::map> unreachableVariables; + std::map stackDeficit; }; } diff --git a/libyul/Dialect.cpp b/libyul/Dialect.cpp index 1003c8e44..6c498ce4c 100644 --- a/libyul/Dialect.cpp +++ b/libyul/Dialect.cpp @@ -33,6 +33,15 @@ Literal Dialect::zeroLiteralForType(solidity::yul::YulString _type) const return {SourceLocation{}, LiteralKind::Number, "0"_yulstring, _type}; } + +Literal Dialect::trueLiteral() const +{ + if (boolType != defaultType) + return {SourceLocation{}, LiteralKind::Boolean, "true"_yulstring, boolType}; + else + return {SourceLocation{}, LiteralKind::Number, "1"_yulstring, defaultType}; +} + bool Dialect::validTypeForLiteral(LiteralKind _kind, YulString, YulString _type) const { if (_kind == LiteralKind::Boolean) diff --git a/libyul/Dialect.h b/libyul/Dialect.h index 6634d6cfd..78b950d58 100644 --- a/libyul/Dialect.h +++ b/libyul/Dialect.h @@ -72,11 +72,15 @@ struct Dialect: boost::noncopyable virtual BuiltinFunction const* equalityFunction(YulString /* _type */) const { return nullptr; } virtual BuiltinFunction const* booleanNegationFunction() const { return nullptr; } + virtual BuiltinFunction const* memoryStoreFunction(YulString /* _type */) const { return nullptr; } + virtual BuiltinFunction const* memoryLoadFunction(YulString /* _type */) const { return nullptr; } + /// Check whether the given type is legal for the given literal value. /// Should only be called if the type exists in the dialect at all. virtual bool validTypeForLiteral(LiteralKind _kind, YulString _value, YulString _type) const; virtual Literal zeroLiteralForType(YulString _type) const; + virtual Literal trueLiteral() const; virtual std::set fixedFunctionNames() const { return {}; } diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 40cfe375f..0ddcf1703 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -193,7 +193,7 @@ private: void visitStatements(std::vector const& _statements); /// Pops all variables declared in the block and checks that the stack height is equal - /// to @a _blackStartStackHeight. + /// to @a _blockStartStackHeight. void finalizeBlock(Block const& _block, int _blockStartStackHeight); void generateMultiAssignment(std::vector const& _variableNames); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index dc648248b..2c3b6be6d 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -142,6 +142,23 @@ map createBuiltins(langutil::EVMVersion _evmVe Expression const& arg = _call.arguments.front(); _assembly.appendLinkerSymbol(std::get(arg).value.str()); })); + + builtins.emplace(createFunction( + "memoryguard", + 1, + 1, + SideEffects{}, + {LiteralKind::Number}, + []( + FunctionCall const& _call, + AbstractAssembly& _assembly, + BuiltinContext&, + function _visitExpression + ) { + visitArguments(_assembly, _call, _visitExpression); + }) + ); + builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index fe1c67a4a..8cac1e0be 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -73,6 +73,8 @@ struct EVMDialect: public Dialect BuiltinFunctionForEVM const* discardFunction(YulString /*_type*/) const override { return builtin("pop"_yulstring); } BuiltinFunctionForEVM const* equalityFunction(YulString /*_type*/) const override { return builtin("eq"_yulstring); } BuiltinFunctionForEVM const* booleanNegationFunction() const override { return builtin("iszero"_yulstring); } + BuiltinFunctionForEVM const* memoryStoreFunction(YulString /*_type*/) const override { return builtin("mstore"_yulstring); } + BuiltinFunctionForEVM const* memoryLoadFunction(YulString /*_type*/) const override { return builtin("mload"_yulstring); } static EVMDialect const& strictAssemblyForEVM(langutil::EVMVersion _version); static EVMDialect const& strictAssemblyForEVMObjects(langutil::EVMVersion _version); diff --git a/libyul/backends/wasm/EVMToEwasmTranslator.cpp b/libyul/backends/wasm/EVMToEwasmTranslator.cpp index 4495ea13b..4f9b0ed08 100644 --- a/libyul/backends/wasm/EVMToEwasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEwasmTranslator.cpp @@ -1211,6 +1211,9 @@ function revert(x1, x2, x3, x4, y1, y2, y3, y4) { function invalid() { unreachable() } +function memoryguard(x:i64) -> y1, y2, y3, y4 { + y4 := x +} } )"}; diff --git a/libyul/optimiser/ExpressionSimplifier.cpp b/libyul/optimiser/ExpressionSimplifier.cpp index ec3a6eb78..623bc12b4 100644 --- a/libyul/optimiser/ExpressionSimplifier.cpp +++ b/libyul/optimiser/ExpressionSimplifier.cpp @@ -22,12 +22,9 @@ #include #include -#include #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; @@ -40,17 +37,7 @@ void ExpressionSimplifier::run(OptimiserStepContext& _context, Block& _ast) void ExpressionSimplifier::visit(Expression& _expression) { ASTModifier::visit(_expression); - while (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_value)) - { - // Do not apply the rule if it removes non-constant parts of the expression. - // TODO: The check could actually be less strict than "movable". - // We only require "Does not cause side-effects". - // Note: References to variables that are only assigned once are always movable, - // so if the value of the variable is not movable, the expression that references - // the variable still is. - if (match->removesNonConstants && !SideEffectsCollector(m_dialect, _expression).movable()) - return; + while (auto const* match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_value)) _expression = match->action().toExpression(locationOf(_expression)); - } } diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h index b8703e2a2..f5e1781cf 100644 --- a/libyul/optimiser/ExpressionSimplifier.h +++ b/libyul/optimiser/ExpressionSimplifier.h @@ -33,7 +33,8 @@ struct OptimiserStepContext; /** * Applies simplification rules to all expressions. * The component will work best if the code is in SSA form, but - * this is not required for correctness. + * this is not required for correctness. Using CommonSubexpressionEliminator + * also helps this component track equivalent sub-expressions. * * It tracks the current values of variables using the DataFlowAnalyzer * and takes them into account for replacements. diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index cd17b7aff..101b89c34 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,9 @@ using namespace solidity::yul; void FullInliner::run(OptimiserStepContext& _context, Block& _ast) { - FullInliner{_ast, _context.dispenser, _context.dialect}.run(); + FullInliner inliner{_ast, _context.dispenser, _context.dialect}; + inliner.run(Pass::InlineTiny); + inliner.run(Pass::InlineRest); } FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect): @@ -72,14 +75,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& } } -void FullInliner::run() +void FullInliner::run(Pass _pass) { - for (auto& statement: m_ast.statements) - if (holds_alternative(statement)) - handleBlock({}, std::get(statement)); - - // TODO it might be good to determine a visiting order: - // first handle functions that are called from many places. + m_pass = _pass; // Note that the order of inlining can result in very different code. // Since AST IDs and thus function names depend on whether or not a contract @@ -87,14 +85,76 @@ void FullInliner::run() // should have as little an impact as possible. This is the case // if we handle inlining in source (and thus, for the IR generator, // function name) order. + // We use stable_sort below to keep the inlining order of two functions + // with the same depth. + map depths = callDepths(); + vector functions; for (auto& statement: m_ast.statements) + if (holds_alternative(statement)) + functions.emplace_back(&std::get(statement)); + std::stable_sort(functions.begin(), functions.end(), [depths]( + FunctionDefinition const* _a, + FunctionDefinition const* _b + ) { + return depths.at(_a->name) < depths.at(_b->name); + }); + for (FunctionDefinition* fun: functions) { - if (!holds_alternative(statement)) - continue; - FunctionDefinition& fun = std::get(statement); - handleBlock(fun.name, fun.body); - updateCodeSize(fun); + handleBlock(fun->name, fun->body); + updateCodeSize(*fun); } + + for (auto& statement: m_ast.statements) + if (holds_alternative(statement)) + handleBlock({}, std::get(statement)); +} + +map FullInliner::callDepths() const +{ + CallGraph cg = CallGraphGenerator::callGraph(m_ast); + cg.functionCalls.erase(""_yulstring); + + // Remove calls to builtin functions. + for (auto& call: cg.functionCalls) + for (auto it = call.second.begin(); it != call.second.end();) + if (m_dialect.builtin(*it)) + it = call.second.erase(it); + else + ++it; + + map depths; + size_t currentDepth = 0; + + while (true) + { + vector removed; + for (auto it = cg.functionCalls.begin(); it != cg.functionCalls.end();) + { + auto const& [fun, callees] = *it; + if (callees.empty()) + { + removed.emplace_back(fun); + depths[fun] = currentDepth; + it = cg.functionCalls.erase(it); + } + else + ++it; + } + + for (auto& call: cg.functionCalls) + call.second -= removed; + + currentDepth++; + + if (removed.empty()) + break; + } + + // Only recursive functions left here. + for (auto const& fun: cg.functionCalls) + depths[fun.first] = currentDepth; + + return depths; } bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) @@ -115,6 +175,10 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) if (size <= 1) return true; + // In the first pass, only inline tiny functions. + if (m_pass == Pass::InlineTiny) + return false; + // Do not inline into already big functions. if (m_functionSizes.at(_callSite) > 45) return false; diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 8092e478e..c0106807a 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -91,13 +91,20 @@ public: void tentativelyUpdateCodeSize(YulString _function, YulString _callSite); private: + enum Pass { InlineTiny, InlineRest }; + FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect); - void run(); + void run(Pass _pass); + + /// @returns a map containing the maximum depths of a call chain starting at each + /// function. For recursive functions, the value is one larger than for all others. + std::map callDepths() const; void updateCodeSize(FunctionDefinition const& _fun); void handleBlock(YulString _currentFunctionName, Block& _block); bool recursive(FunctionDefinition const& _fun) const; + Pass m_pass; /// The AST to be modified. The root block itself will not be modified, because /// we store pointers to functions. Block& m_ast; diff --git a/libyul/optimiser/FunctionCallFinder.cpp b/libyul/optimiser/FunctionCallFinder.cpp new file mode 100644 index 000000000..d5a6afcc9 --- /dev/null +++ b/libyul/optimiser/FunctionCallFinder.cpp @@ -0,0 +1,39 @@ +/* + 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 + +using namespace std; +using namespace solidity; +using namespace solidity::yul; + +vector FunctionCallFinder::run(Block& _block, YulString _functionName) +{ + FunctionCallFinder functionCallFinder(_functionName); + functionCallFinder(_block); + return functionCallFinder.m_calls; +} + +FunctionCallFinder::FunctionCallFinder(YulString _functionName): m_functionName(_functionName) {} + +void FunctionCallFinder::operator()(FunctionCall& _functionCall) +{ + ASTModifier::operator()(_functionCall); + if (_functionCall.functionName.name == m_functionName) + m_calls.emplace_back(&_functionCall); +} \ No newline at end of file diff --git a/libyul/optimiser/FunctionCallFinder.h b/libyul/optimiser/FunctionCallFinder.h new file mode 100644 index 000000000..365f86688 --- /dev/null +++ b/libyul/optimiser/FunctionCallFinder.h @@ -0,0 +1,47 @@ +/* + 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 . +*/ +/** + * AST walker that finds all calls to a function of a given name. + */ + +#pragma once + +#include + +#include + +namespace solidity::yul +{ + +/** + * AST walker that finds all calls to a function of a given name. + * + * Prerequisite: Disambiguator + */ +class FunctionCallFinder: ASTModifier +{ +public: + static std::vector run(Block& _block, YulString _functionName); +private: + FunctionCallFinder(YulString _functionName); + using ASTModifier::operator(); + void operator()(FunctionCall& _functionCall) override; + YulString m_functionName; + std::vector m_calls; +}; + +} diff --git a/libyul/optimiser/FunctionGrouper.h b/libyul/optimiser/FunctionGrouper.h index 0bfbb2f06..ead0ddc11 100644 --- a/libyul/optimiser/FunctionGrouper.h +++ b/libyul/optimiser/FunctionGrouper.h @@ -16,7 +16,7 @@ */ // SPDX-License-Identifier: GPL-3.0 /** - * Optimiser component that changes the code of a black so that all non-function definition + * Optimiser component that changes the code of a block so that all non-function definition * instructions are moved to a block of their own followed by all function definitions. */ diff --git a/libyul/optimiser/NameDisplacer.h b/libyul/optimiser/NameDisplacer.h index d1b3e4363..336dd04e4 100644 --- a/libyul/optimiser/NameDisplacer.h +++ b/libyul/optimiser/NameDisplacer.h @@ -60,6 +60,8 @@ public: void operator()(FunctionCall& _funCall) override; void operator()(Block& _block) override; + std::map const& translations() const { return m_translations; } + protected: /// Check if the newly introduced identifier @a _name has to be replaced. void checkAndReplaceNew(YulString& _name); diff --git a/libyul/optimiser/NameSimplifier.cpp b/libyul/optimiser/NameSimplifier.cpp new file mode 100644 index 000000000..2e1bb822a --- /dev/null +++ b/libyul/optimiser/NameSimplifier.cpp @@ -0,0 +1,122 @@ +/* + 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 + +using namespace solidity::yul; +using namespace std; + +NameSimplifier::NameSimplifier( + OptimiserStepContext& _context, + Block const& _ast +): + m_context(_context), + m_usedNames(_context.reservedIdentifiers) +{ + for (YulString name: m_usedNames) + m_translations[name] = name; + + set allNames = NameCollector(_ast).names(); + m_usedNames += allNames; + for (YulString name: allNames) + findSimplification(name); +} + +void NameSimplifier::operator()(FunctionDefinition& _funDef) +{ + translate(_funDef.name); + renameVariables(_funDef.parameters); + renameVariables(_funDef.returnVariables); + ASTModifier::operator()(_funDef); +} + +void NameSimplifier::operator()(VariableDeclaration& _varDecl) +{ + renameVariables(_varDecl.variables); + ASTModifier::operator()(_varDecl); +} + +void NameSimplifier::renameVariables(vector& _variables) +{ + for (TypedName& typedName: _variables) + translate(typedName.name); +} + +void NameSimplifier::operator()(Identifier& _identifier) +{ + translate(_identifier.name); +} + +void NameSimplifier::operator()(FunctionCall& _funCall) +{ + // The visitor on its own does not visit the function name. + if (!m_context.dialect.builtin(_funCall.functionName.name)) + (*this)(_funCall.functionName); + ASTModifier::operator()(_funCall); +} + +void NameSimplifier::findSimplification(YulString _name) +{ + if (m_translations.count(_name)) + return; + + string name = _name.str(); + + static auto replacements = vector>{ + {regex("_\\$\\d+"), ""}, // removes AST IDs + {regex("(abi_..code.*)_to_.*"), "$1"}, // removes _to... for abi functions + {regex("(stringliteral_[0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]*"), "$1"}, // shorten string literal + {regex("tuple_t_"), ""}, + {regex("_memory_ptr"), ""}, + {regex("_calldata_ptr"), "_calldata"}, + {regex("_fromStack"), ""}, + {regex("_storage_storage"), "_storage"}, + {regex("_memory_memory"), "_memory"}, + {regex("t_contract\\$_([^_]*)_"), "$1_"}, + {regex("index_access_t_array"), "index_access"}, + {regex("[0-9]*_$"), ""} + }; + for (auto const& [pattern, substitute]: replacements) + { + string candidate = regex_replace(name, pattern, substitute); + if ( + !isRestrictedIdentifier(m_context.dialect, YulString(candidate)) && + !m_usedNames.count(YulString(candidate)) + ) + name = candidate; + } + if (name != _name.str()) + { + m_usedNames.insert(YulString(name)); + m_translations[_name] = YulString(name); + } +} + +void NameSimplifier::translate(YulString& _name) +{ + auto it = m_translations.find(_name); + if (it != m_translations.end()) + _name = it->second; +} diff --git a/libyul/optimiser/NameSimplifier.h b/libyul/optimiser/NameSimplifier.h new file mode 100644 index 000000000..924e734f9 --- /dev/null +++ b/libyul/optimiser/NameSimplifier.h @@ -0,0 +1,76 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace solidity::yul +{ + +struct Dialect; + +/** + * Pass to "simplify" all identifier names. + * + * The purpose of this is to make generated code more readable, but also + * to remove AST identifiers that could lead to a different sorting order + * and thus influence e.g. the order of function inlining. + * + * Prerequisites: Disambiguator, FunctionHoister, FunctionGrouper + */ +class NameSimplifier: public ASTModifier +{ +public: + static constexpr char const* name{"NameSimplifier"}; + static void run(OptimiserStepContext& _context, Block& _ast) + { + NameSimplifier{_context, _ast}(_ast); + } + + using ASTModifier::operator(); + void operator()(VariableDeclaration& _varDecl) override; + void operator()(Identifier& _identifier) override; + void operator()(FunctionCall& _funCall) override; + void operator()(FunctionDefinition& _funDef) override; + +private: + NameSimplifier( + OptimiserStepContext& _context, + Block const& _ast + ); + + /// Tries to rename a list of variables. + void renameVariables(std::vector& _variables); + + void findSimplification(YulString _name); + void translate(YulString& _name); + + OptimiserStepContext& m_context; + std::set m_usedNames; + std::map m_translations; +}; + +} diff --git a/libyul/optimiser/OptimiserStep.h b/libyul/optimiser/OptimiserStep.h index 3da161957..70ed098a8 100644 --- a/libyul/optimiser/OptimiserStep.h +++ b/libyul/optimiser/OptimiserStep.h @@ -20,6 +20,7 @@ #include +#include #include #include @@ -49,17 +50,41 @@ struct OptimiserStep virtual ~OptimiserStep() = default; virtual void run(OptimiserStepContext&, Block&) const = 0; + /// @returns non-nullopt if the step cannot be run, for example because it requires + /// an SMT solver to be loaded, but none is available. In that case, the string + /// contains a human-readable reason. + virtual std::optional invalidInCurrentEnvironment() const = 0; std::string name; }; template struct OptimiserStepInstance: public OptimiserStep { +private: + template + struct HasInvalidInCurrentEnvironmentMethod + { + private: + template static auto test(int) -> decltype(U::invalidInCurrentEnvironment(), std::true_type()); + template static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + +public: OptimiserStepInstance(): OptimiserStep{Step::name} {} void run(OptimiserStepContext& _context, Block& _ast) const override { Step::run(_context, _ast); } + std::optional invalidInCurrentEnvironment() const override + { + if constexpr (HasInvalidInCurrentEnvironmentMethod::value) + return Step::invalidInCurrentEnvironment(); + else + return std::nullopt; + }; }; diff --git a/libyul/optimiser/ReasoningBasedSimplifier.cpp b/libyul/optimiser/ReasoningBasedSimplifier.cpp new file mode 100644 index 000000000..ea464f248 --- /dev/null +++ b/libyul/optimiser/ReasoningBasedSimplifier.cpp @@ -0,0 +1,337 @@ +/* + 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 + +#include +#include + +#include +#include + +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::yul; +using namespace solidity::smtutil; + +void ReasoningBasedSimplifier::run(OptimiserStepContext& _context, Block& _ast) +{ + set ssaVars = SSAValueTracker::ssaVariables(_ast); + ReasoningBasedSimplifier{_context.dialect, ssaVars}(_ast); +} + +std::optional ReasoningBasedSimplifier::invalidInCurrentEnvironment() +{ + // SMTLib2 interface is always available, but we would like to have synchronous answers. + if (smtutil::SMTPortfolio{}.solvers() <= 1) + return string{"No SMT solvers available."}; + else + return nullopt; +} + +void ReasoningBasedSimplifier::operator()(VariableDeclaration& _varDecl) +{ + if (_varDecl.variables.size() != 1 || !_varDecl.value) + return; + YulString varName = _varDecl.variables.front().name; + if (!m_ssaVariables.count(varName)) + return; + bool const inserted = m_variables.insert({varName, m_solver->newVariable("yul_" + varName.str(), defaultSort())}).second; + yulAssert(inserted, ""); + m_solver->addAssertion(m_variables.at(varName) == encodeExpression(*_varDecl.value)); +} + +void ReasoningBasedSimplifier::operator()(If& _if) +{ + if (!SideEffectsCollector{m_dialect, *_if.condition}.movable()) + return; + + smtutil::Expression condition = encodeExpression(*_if.condition); + m_solver->push(); + m_solver->addAssertion(condition == constantValue(0)); + CheckResult result = m_solver->check({}).first; + m_solver->pop(); + if (result == CheckResult::UNSATISFIABLE) + { + Literal trueCondition = m_dialect.trueLiteral(); + trueCondition.location = locationOf(*_if.condition); + _if.condition = make_unique(move(trueCondition)); + } + else + { + m_solver->push(); + m_solver->addAssertion(condition != constantValue(0)); + CheckResult result2 = m_solver->check({}).first; + m_solver->pop(); + if (result2 == CheckResult::UNSATISFIABLE) + { + Literal falseCondition = m_dialect.zeroLiteralForType(m_dialect.boolType); + falseCondition.location = locationOf(*_if.condition); + _if.condition = make_unique(move(falseCondition)); + _if.body = yul::Block{}; + // Nothing left to be done. + return; + } + } + + m_solver->push(); + m_solver->addAssertion(condition != constantValue(0)); + + ASTModifier::operator()(_if.body); + + m_solver->pop(); +} + +ReasoningBasedSimplifier::ReasoningBasedSimplifier( + Dialect const& _dialect, + set const& _ssaVariables +): + m_dialect(_dialect), + m_ssaVariables(_ssaVariables), + m_solver(make_unique()) +{ +} + +smtutil::Expression ReasoningBasedSimplifier::encodeExpression(yul::Expression const& _expression) +{ + return std::visit(GenericVisitor{ + [&](FunctionCall const& _functionCall) + { + if (auto const* dialect = dynamic_cast(&m_dialect)) + if (auto const* builtin = dialect->builtin(_functionCall.functionName.name)) + if (builtin->instruction) + return encodeEVMBuiltin(*builtin->instruction, _functionCall.arguments); + return newRestrictedVariable(); + }, + [&](Identifier const& _identifier) + { + if ( + m_ssaVariables.count(_identifier.name) && + m_variables.count(_identifier.name) + ) + return m_variables.at(_identifier.name); + else + return newRestrictedVariable(); + }, + [&](Literal const& _literal) + { + return literalValue(_literal); + } + }, _expression); +} + +smtutil::Expression ReasoningBasedSimplifier::encodeEVMBuiltin( + evmasm::Instruction _instruction, + vector const& _arguments +) +{ + vector arguments = applyMap( + _arguments, + [this](yul::Expression const& _expr) { return encodeExpression(_expr); } + ); + switch (_instruction) + { + case evmasm::Instruction::ADD: + return wrap(arguments.at(0) + arguments.at(1)); + case evmasm::Instruction::MUL: + return wrap(arguments.at(0) * arguments.at(1)); + case evmasm::Instruction::SUB: + return wrap(arguments.at(0) - arguments.at(1)); + case evmasm::Instruction::DIV: + return smtutil::Expression::ite( + arguments.at(1) == constantValue(0), + constantValue(0), + arguments.at(0) / arguments.at(1) + ); + case evmasm::Instruction::SDIV: + return smtutil::Expression::ite( + arguments.at(1) == constantValue(0), + constantValue(0), + // No `wrap()` needed here, because -2**255 / -1 results + // in 2**255 which is "converted" to its two's complement + // representation 2**255 in `signedToUnsigned` + signedToUnsigned(smtutil::signedDivisionEVM( + unsignedToSigned(arguments.at(0)), + unsignedToSigned(arguments.at(1)) + )) + ); + case evmasm::Instruction::MOD: + return smtutil::Expression::ite( + arguments.at(1) == constantValue(0), + constantValue(0), + arguments.at(0) % arguments.at(1) + ); + case evmasm::Instruction::SMOD: + return smtutil::Expression::ite( + arguments.at(1) == constantValue(0), + constantValue(0), + signedToUnsigned(signedModuloEVM( + unsignedToSigned(arguments.at(0)), + unsignedToSigned(arguments.at(1)) + )) + ); + case evmasm::Instruction::LT: + return booleanValue(arguments.at(0) < arguments.at(1)); + case evmasm::Instruction::SLT: + return booleanValue(unsignedToSigned(arguments.at(0)) < unsignedToSigned(arguments.at(1))); + case evmasm::Instruction::GT: + return booleanValue(arguments.at(0) > arguments.at(1)); + case evmasm::Instruction::SGT: + return booleanValue(unsignedToSigned(arguments.at(0)) > unsignedToSigned(arguments.at(1))); + case evmasm::Instruction::EQ: + return booleanValue(arguments.at(0) == arguments.at(1)); + case evmasm::Instruction::ISZERO: + return booleanValue(arguments.at(0) == constantValue(0)); + case evmasm::Instruction::AND: + return smtutil::Expression::ite( + (arguments.at(0) == 0 || arguments.at(0) == 1) && + (arguments.at(1) == 0 || arguments.at(1) == 1), + booleanValue(arguments.at(0) == 1 && arguments.at(1) == 1), + bv2int(int2bv(arguments.at(0)) & int2bv(arguments.at(1))) + ); + case evmasm::Instruction::OR: + return smtutil::Expression::ite( + (arguments.at(0) == 0 || arguments.at(0) == 1) && + (arguments.at(1) == 0 || arguments.at(1) == 1), + booleanValue(arguments.at(0) == 1 || arguments.at(1) == 1), + bv2int(int2bv(arguments.at(0)) | int2bv(arguments.at(1))) + ); + case evmasm::Instruction::XOR: + return bv2int(int2bv(arguments.at(0)) ^ int2bv(arguments.at(1))); + case evmasm::Instruction::NOT: + return smtutil::Expression(u256(-1)) - arguments.at(0); + case evmasm::Instruction::SHL: + return smtutil::Expression::ite( + arguments.at(0) > 255, + constantValue(0), + bv2int(int2bv(arguments.at(1)) << int2bv(arguments.at(0))) + ); + case evmasm::Instruction::SHR: + return smtutil::Expression::ite( + arguments.at(0) > 255, + constantValue(0), + bv2int(int2bv(arguments.at(1)) >> int2bv(arguments.at(0))) + ); + case evmasm::Instruction::SAR: + return smtutil::Expression::ite( + arguments.at(0) > 255, + constantValue(0), + bv2int(smtutil::Expression::ashr(int2bv(arguments.at(1)), int2bv(arguments.at(0)))) + ); + case evmasm::Instruction::ADDMOD: + return smtutil::Expression::ite( + arguments.at(2) == constantValue(0), + constantValue(0), + (arguments.at(0) + arguments.at(1)) % arguments.at(2) + ); + case evmasm::Instruction::MULMOD: + return smtutil::Expression::ite( + arguments.at(2) == constantValue(0), + constantValue(0), + (arguments.at(0) * arguments.at(1)) % arguments.at(2) + ); + // TODO SIGNEXTEND + default: + break; + } + return newRestrictedVariable(); +} + +smtutil::Expression ReasoningBasedSimplifier::int2bv(smtutil::Expression _arg) const +{ + return smtutil::Expression::int2bv(std::move(_arg), 256); +} + +smtutil::Expression ReasoningBasedSimplifier::bv2int(smtutil::Expression _arg) const +{ + return smtutil::Expression::bv2int(std::move(_arg)); +} + +smtutil::Expression ReasoningBasedSimplifier::newVariable() +{ + return m_solver->newVariable(uniqueName(), defaultSort()); +} + +smtutil::Expression ReasoningBasedSimplifier::newRestrictedVariable() +{ + smtutil::Expression var = newVariable(); + m_solver->addAssertion(0 <= var && var < smtutil::Expression(bigint(1) << 256)); + return var; +} + +string ReasoningBasedSimplifier::uniqueName() +{ + return "expr_" + to_string(m_varCounter++); +} + +shared_ptr ReasoningBasedSimplifier::defaultSort() const +{ + return SortProvider::intSort(); +} + +smtutil::Expression ReasoningBasedSimplifier::booleanValue(smtutil::Expression _value) const +{ + return smtutil::Expression::ite(_value, constantValue(1), constantValue(0)); +} + +smtutil::Expression ReasoningBasedSimplifier::constantValue(size_t _value) const +{ + return _value; +} + +smtutil::Expression ReasoningBasedSimplifier::literalValue(Literal const& _literal) const +{ + return smtutil::Expression(valueOfLiteral(_literal)); +} + +smtutil::Expression ReasoningBasedSimplifier::unsignedToSigned(smtutil::Expression _value) +{ + return smtutil::Expression::ite( + _value < smtutil::Expression(bigint(1) << 255), + _value, + _value - smtutil::Expression(bigint(1) << 256) + ); +} + +smtutil::Expression ReasoningBasedSimplifier::signedToUnsigned(smtutil::Expression _value) +{ + return smtutil::Expression::ite( + _value >= 0, + _value, + _value + smtutil::Expression(bigint(1) << 256) + ); +} + +smtutil::Expression ReasoningBasedSimplifier::wrap(smtutil::Expression _value) +{ + smtutil::Expression rest = newRestrictedVariable(); + smtutil::Expression multiplier = newVariable(); + m_solver->addAssertion(_value == multiplier * smtutil::Expression(bigint(1) << 256) + rest); + return rest; +} diff --git a/libyul/optimiser/ReasoningBasedSimplifier.h b/libyul/optimiser/ReasoningBasedSimplifier.h new file mode 100644 index 000000000..18fcf3583 --- /dev/null +++ b/libyul/optimiser/ReasoningBasedSimplifier.h @@ -0,0 +1,98 @@ +/* + 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 + +// because of instruction +#include + +#include + +namespace solidity::smtutil +{ +class SolverInterface; +class Expression; +struct Sort; +} + +namespace solidity::yul +{ + +/** + * Reasoning-based simplifier. + * This optimizer uses SMT solvers to check whether `if` conditions are constant. + * - If `constraints AND condition` is UNSAT, the condition is never true and the whole body can be removed. + * - If `constraints AND NOT condition` is UNSAT, the condition is always true and can be replaced by `1`. + * The simplifications above can only be applied if the condition is movable. + * + * It is only effective on the EVM dialect, but safe to use on other dialects. + * + * Prerequisite: Disambiguator, SSATransform. + */ +class ReasoningBasedSimplifier: public ASTModifier +{ +public: + static constexpr char const* name{"ReasoningBasedSimplifier"}; + static void run(OptimiserStepContext& _context, Block& _ast); + static std::optional invalidInCurrentEnvironment(); + + using ASTModifier::operator(); + void operator()(VariableDeclaration& _varDecl) override; + void operator()(If& _if) override; + +private: + explicit ReasoningBasedSimplifier( + Dialect const& _dialect, + std::set const& _ssaVariables + ); + + smtutil::Expression encodeExpression( + Expression const& _expression + ); + + virtual smtutil::Expression encodeEVMBuiltin( + evmasm::Instruction _instruction, + std::vector const& _arguments + ); + + smtutil::Expression int2bv(smtutil::Expression _arg) const; + smtutil::Expression bv2int(smtutil::Expression _arg) const; + + smtutil::Expression newVariable(); + virtual smtutil::Expression newRestrictedVariable(); + std::string uniqueName(); + + virtual std::shared_ptr defaultSort() const; + virtual smtutil::Expression booleanValue(smtutil::Expression _value) const; + virtual smtutil::Expression constantValue(size_t _value) const; + virtual smtutil::Expression literalValue(Literal const& _literal) const; + virtual smtutil::Expression unsignedToSigned(smtutil::Expression _value); + virtual smtutil::Expression signedToUnsigned(smtutil::Expression _value); + virtual smtutil::Expression wrap(smtutil::Expression _value); + + Dialect const& m_dialect; + std::set const& m_ssaVariables; + std::unique_ptr m_solver; + std::map m_variables; + + size_t m_varCounter = 0; +}; + +} diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index 2fe5de3e5..cb797975b 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -171,12 +171,22 @@ bool Pattern::matches( return false; assertThrow(m_arguments.size() == instrAndArgs->second->size(), OptimizerException, ""); for (size_t i = 0; i < m_arguments.size(); ++i) - if (!m_arguments[i].matches(instrAndArgs->second->at(i), _dialect, _ssaValues)) + { + Expression const& arg = instrAndArgs->second->at(i); + // If this is a direct function call instead of a variable or literal, + // we reject the match because side-effects could prevent us from + // arbitrarily modifying the code. + if ( + holds_alternative(arg) || + !m_arguments[i].matches(arg, _dialect, _ssaValues) + ) return false; + } } else { assertThrow(m_arguments.empty(), OptimizerException, "\"Any\" should not have arguments."); + assertThrow(!holds_alternative(*expr), OptimizerException, "\"Any\" at top-level."); } if (m_matchGroup) @@ -197,9 +207,14 @@ bool Pattern::matches( assertThrow(m_kind == PatternKind::Any, OptimizerException, "Match group repetition for non-any."); Expression const* firstMatch = (*m_matchGroups)[m_matchGroup]; assertThrow(firstMatch, OptimizerException, "Match set but to null."); - return - SyntacticallyEqual{}(*firstMatch, _expr) && - SideEffectsCollector(_dialect, _expr).movable(); + assertThrow( + !holds_alternative(_expr) && + !holds_alternative(*firstMatch), + OptimizerException, + "Group matches have to be literals or variables." + ); + + return SyntacticallyEqual{}(*firstMatch, _expr); } else if (m_kind == PatternKind::Any) (*m_matchGroups)[m_matchGroup] = &_expr; diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index d011c64b8..98850f03e 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -168,7 +168,7 @@ bool StackCompressor::run( bool allowMSizeOptimzation = !MSizeFinder::containsMSize(_dialect, *_object.code); for (size_t iterations = 0; iterations < _maxIterations; iterations++) { - map stackSurplus = CompilabilityChecker::run(_dialect, _object, _optimizeStackAllocation); + map stackSurplus = CompilabilityChecker(_dialect, _object, _optimizeStackAllocation).stackDeficit; if (stackSurplus.empty()) return true; diff --git a/libyul/optimiser/StackLimitEvader.cpp b/libyul/optimiser/StackLimitEvader.cpp new file mode 100644 index 000000000..98be932cb --- /dev/null +++ b/libyul/optimiser/StackLimitEvader.cpp @@ -0,0 +1,145 @@ +/* + 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 +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::yul; + +namespace +{ +/** + * Walks the call graph using a Depth-First-Search assigning memory slots to variables. + * - The leaves of the call graph will get the lowest slot, increasing towards the root. + * - ``slotsRequiredForFunction`` maps a function to the number of slots it requires (which is also the + * next available slot that can be used by another function that calls this function). + * - For each function starting from the root of the call graph: + * - Visit all children that are not already visited. + * - Determine the maximum value ``n`` of the values of ``slotsRequiredForFunction`` among the children. + * - If the function itself contains variables that need memory slots, but is contained in a cycle, + * abort the process as failure. + * - If not, assign each variable its slot starting from ``n`` (incrementing it). + * - Assign ``n`` to ``slotsRequiredForFunction`` of the function. + */ +struct MemoryOffsetAllocator +{ + uint64_t run(YulString _function = YulString{}) + { + if (slotsRequiredForFunction.count(_function)) + return slotsRequiredForFunction[_function]; + + // Assign to zero early to guard against recursive calls. + slotsRequiredForFunction[_function] = 0; + + uint64_t requiredSlots = 0; + if (callGraph.count(_function)) + for (YulString child: callGraph.at(_function)) + requiredSlots = std::max(run(child), requiredSlots); + + if (unreachableVariables.count(_function)) + { + yulAssert(!slotAllocations.count(_function), ""); + auto& assignedSlots = slotAllocations[_function]; + for (YulString variable: unreachableVariables.at(_function)) + if (variable.empty()) + { + // TODO: Too many function arguments or return parameters. + } + else + assignedSlots[variable] = requiredSlots++; + } + + return slotsRequiredForFunction[_function] = requiredSlots; + } + + map> const& unreachableVariables; + map> const& callGraph; + + map> slotAllocations{}; + map slotsRequiredForFunction{}; +}; + +u256 literalArgumentValue(FunctionCall const& _call) +{ + yulAssert(_call.arguments.size() == 1, ""); + Literal const* literal = std::get_if(&_call.arguments.front()); + yulAssert(literal && literal->kind == LiteralKind::Number, ""); + return valueOfLiteral(*literal); +} +} + +void StackLimitEvader::run( + OptimiserStepContext& _context, + Object& _object, + map> const& _unreachableVariables +) +{ + yulAssert(_object.code, ""); + auto const* evmDialect = dynamic_cast(&_context.dialect); + yulAssert( + evmDialect && evmDialect->providesObjectAccess(), + "StackLimitEvader can only be run on objects using the EVMDialect with object access." + ); + + vector memoryGuardCalls = FunctionCallFinder::run( + *_object.code, + "memoryguard"_yulstring + ); + // Do not optimise, if no ``memoryguard`` call is found. + if (memoryGuardCalls.empty()) + return; + + // Make sure all calls to ``memoryguard`` we found have the same value as argument (otherwise, abort). + u256 reservedMemory = literalArgumentValue(*memoryGuardCalls.front()); + for (FunctionCall const* memoryGuardCall: memoryGuardCalls) + if (reservedMemory != literalArgumentValue(*memoryGuardCall)) + return; + + CallGraph callGraph = CallGraphGenerator::callGraph(*_object.code); + + // We cannot move variables in recursive functions to fixed memory offsets. + for (YulString function: callGraph.recursiveFunctions()) + if (_unreachableVariables.count(function)) + return; + + MemoryOffsetAllocator memoryOffsetAllocator{_unreachableVariables, callGraph.functionCalls}; + uint64_t requiredSlots = memoryOffsetAllocator.run(); + + StackToMemoryMover::run(_context, reservedMemory, memoryOffsetAllocator.slotAllocations, requiredSlots, *_object.code); + + yulAssert(requiredSlots < std::numeric_limits::max() / 32, ""); + reservedMemory += 32 * requiredSlots; + for (FunctionCall* memoryGuardCall: FunctionCallFinder::run(*_object.code, "memoryguard"_yulstring)) + { + Literal* literal = std::get_if(&memoryGuardCall->arguments.front()); + yulAssert(literal && literal->kind == LiteralKind::Number, ""); + literal->value = YulString{util::toCompactHexWithPrefix(reservedMemory)}; + } +} diff --git a/libyul/optimiser/StackLimitEvader.h b/libyul/optimiser/StackLimitEvader.h new file mode 100644 index 000000000..4fc351f73 --- /dev/null +++ b/libyul/optimiser/StackLimitEvader.h @@ -0,0 +1,66 @@ +/* + 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 . +*/ +/** + * Optimisation stage that assigns memory offsets to variables that would become unreachable if + * assigned a stack slot as usual and replaces references and assignments to them by mload and mstore calls. + */ + +#pragma once + +#include + +namespace solidity::yul +{ + +struct Object; + +/** + * Optimisation stage that assigns memory offsets to variables that would become unreachable if + * assigned a stack slot as usual. + * + * Uses CompilabilityChecker to determine which variables in which functions are unreachable. + * + * Only variables outside of functions contained in cycles in the call graph are considered. Thereby it is possible + * to assign globally fixed memory offsets to the variable. If a variable in a function contained in a cycle in the + * call graph is reported as unreachable, the process is aborted. + * + * Offsets are assigned to the variables, s.t. on every path through the call graph each variable gets a unique offset + * in memory. However, distinct paths through the call graph can use the same memory offsets for their variables. + * + * The current arguments to the ``memoryguard`` calls are used as base memory offset and then replaced by the offset past + * the last memory offset used for a variable on any path through the call graph. + * + * Finally, the StackToMemoryMover is called to actually move the variables to their offsets in memory. + * + * Prerequisite: Disambiguator + */ +class StackLimitEvader +{ +public: + /// @a _unreachableVariables can be determined by the CompilabilityChecker. + /// Can only be run on the EVM dialect with objects. + /// Abort and do nothing, if no ``memoryguard`` call or several ``memoryguard`` calls + /// with non-matching arguments are found, or if any of the @a _unreachableVariables + /// are contained in a recursive function. + static void run( + OptimiserStepContext& _context, + Object& _object, + std::map> const& _unreachableVariables + ); +}; + +} diff --git a/libyul/optimiser/StackToMemoryMover.cpp b/libyul/optimiser/StackToMemoryMover.cpp new file mode 100644 index 000000000..385d508f2 --- /dev/null +++ b/libyul/optimiser/StackToMemoryMover.cpp @@ -0,0 +1,235 @@ +/* + 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 + +using namespace std; +using namespace solidity; +using namespace solidity::yul; + +namespace +{ +vector generateMemoryStore( + Dialect const& _dialect, + langutil::SourceLocation const& _loc, + YulString _mpos, + Expression _value +) +{ + BuiltinFunction const* memoryStoreFunction = _dialect.memoryStoreFunction(_dialect.defaultType); + yulAssert(memoryStoreFunction, ""); + vector result; + result.emplace_back(ExpressionStatement{_loc, FunctionCall{ + _loc, + Identifier{_loc, memoryStoreFunction->name}, + { + Literal{_loc, LiteralKind::Number, _mpos, {}}, + std::move(_value) + } + }}); + return result; +} +} + +void StackToMemoryMover::run( + OptimiserStepContext& _context, + u256 _reservedMemory, + map> const& _memorySlots, + uint64_t _numRequiredSlots, + Block& _block +) +{ + StackToMemoryMover stackToMemoryMover(_context, _reservedMemory, _memorySlots, _numRequiredSlots); + stackToMemoryMover(_block); +} + +StackToMemoryMover::StackToMemoryMover( + OptimiserStepContext& _context, + u256 _reservedMemory, + map> const& _memorySlots, + uint64_t _numRequiredSlots +): +m_context(_context), +m_reservedMemory(std::move(_reservedMemory)), +m_memorySlots(_memorySlots), +m_numRequiredSlots(_numRequiredSlots), +m_nameDispenser(_context.dispenser) +{ + auto const* evmDialect = dynamic_cast(&_context.dialect); + yulAssert( + evmDialect && evmDialect->providesObjectAccess(), + "StackToMemoryMover can only be run on objects using the EVMDialect with object access." + ); + + if (m_memorySlots.count(YulString{})) + // If the global scope contains variables to be moved, start with those as if it were a function. + m_currentFunctionMemorySlots = &m_memorySlots.at(YulString{}); +} + +void StackToMemoryMover::operator()(FunctionDefinition& _functionDefinition) +{ + if (m_memorySlots.count(_functionDefinition.name)) + { + map const* saved = m_currentFunctionMemorySlots; + m_currentFunctionMemorySlots = &m_memorySlots.at(_functionDefinition.name); + for (TypedName const& param: _functionDefinition.parameters + _functionDefinition.returnVariables) + if (m_currentFunctionMemorySlots->count(param.name)) + { + // TODO: we cannot handle function parameters yet. + m_currentFunctionMemorySlots = saved; + return; + } + ASTModifier::operator()(_functionDefinition); + m_currentFunctionMemorySlots = saved; + } +} + +void StackToMemoryMover::operator()(Block& _block) +{ + using OptionalStatements = std::optional>; + if (!m_currentFunctionMemorySlots) + { + ASTModifier::operator()(_block); + return; + } + auto containsVariableNeedingEscalation = [&](auto const& _variables) { + return util::contains_if(_variables, [&](auto const& var) { + return m_currentFunctionMemorySlots->count(var.name); + }); + }; + auto rewriteAssignmentOrVariableDeclaration = [&]( + langutil::SourceLocation const& _loc, + auto const& _variables, + std::unique_ptr _value + ) -> std::vector { + if (_variables.size() == 1) + return generateMemoryStore( + m_context.dialect, + _loc, + memoryOffset(_variables.front().name), + _value ? *std::move(_value) : Literal{_loc, LiteralKind::Number, "0"_yulstring, {}} + ); + + VariableDeclaration tempDecl{_loc, {}, std::move(_value)}; + vector memoryAssignments; + vector variableAssignments; + for (auto& var: _variables) + { + YulString tempVarName = m_nameDispenser.newName(var.name); + tempDecl.variables.emplace_back(TypedName{var.location, tempVarName, {}}); + + if (m_currentFunctionMemorySlots->count(var.name)) + memoryAssignments += generateMemoryStore( + m_context.dialect, + _loc, + memoryOffset(var.name), + Identifier{_loc, tempVarName} + ); + else if constexpr (std::is_same_v, Identifier>) + variableAssignments.emplace_back(Assignment{ + _loc, { Identifier{var.location, var.name} }, + make_unique(Identifier{_loc, tempVarName}) + }); + else + variableAssignments.emplace_back(VariableDeclaration{ + _loc, {std::move(var)}, + make_unique(Identifier{_loc, tempVarName}) + }); + } + std::vector result; + result.emplace_back(std::move(tempDecl)); + std::reverse(memoryAssignments.begin(), memoryAssignments.end()); + result += std::move(memoryAssignments); + std::reverse(variableAssignments.begin(), variableAssignments.end()); + result += std::move(variableAssignments); + return result; + }; + + util::iterateReplacing( + _block.statements, + [&](Statement& _statement) + { + auto defaultVisit = [&]() { ASTModifier::visit(_statement); return OptionalStatements{}; }; + return std::visit(util::GenericVisitor{ + [&](Assignment& _assignment) -> OptionalStatements + { + if (!containsVariableNeedingEscalation(_assignment.variableNames)) + return defaultVisit(); + visit(*_assignment.value); + return {rewriteAssignmentOrVariableDeclaration( + _assignment.location, + _assignment.variableNames, + std::move(_assignment.value) + )}; + }, + [&](VariableDeclaration& _varDecl) -> OptionalStatements + { + if (!containsVariableNeedingEscalation(_varDecl.variables)) + return defaultVisit(); + if (_varDecl.value) + visit(*_varDecl.value); + return {rewriteAssignmentOrVariableDeclaration( + _varDecl.location, + _varDecl.variables, + std::move(_varDecl.value) + )}; + }, + [&](auto&) { return defaultVisit(); } + }, _statement); + }); +} + +void StackToMemoryMover::visit(Expression& _expression) +{ + if ( + Identifier* identifier = std::get_if(&_expression); + identifier && m_currentFunctionMemorySlots && m_currentFunctionMemorySlots->count(identifier->name) + ) + { + BuiltinFunction const* memoryLoadFunction = m_context.dialect.memoryLoadFunction(m_context.dialect.defaultType); + yulAssert(memoryLoadFunction, ""); + langutil::SourceLocation loc = identifier->location; + _expression = FunctionCall{ + loc, + Identifier{loc, memoryLoadFunction->name}, { + Literal{ + loc, + LiteralKind::Number, + memoryOffset(identifier->name), + {} + } + } + }; + } + else + ASTModifier::visit(_expression); +} + +YulString StackToMemoryMover::memoryOffset(YulString _variable) +{ + yulAssert(m_currentFunctionMemorySlots, ""); + uint64_t slot = m_currentFunctionMemorySlots->at(_variable); + yulAssert(slot < m_numRequiredSlots, ""); + return YulString{util::toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))}; +} + diff --git a/libyul/optimiser/StackToMemoryMover.h b/libyul/optimiser/StackToMemoryMover.h new file mode 100644 index 000000000..ea38ea119 --- /dev/null +++ b/libyul/optimiser/StackToMemoryMover.h @@ -0,0 +1,121 @@ +/* + 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 . +*/ +/** + * Optimisation stage that moves Yul variables from stack to memory. + */ + +#pragma once + +#include +#include +#include + +namespace solidity::yul +{ + +/** + * Optimisation stage that moves Yul variables from stack to memory. + * It takes a map from functions names and variable names to memory offsets. + * It then transforms the AST as follows: + * + * Single variable declarations are replaced by mstore's as follows: + * If a is in the map, replace + * let a + * by + * mstore(, 0) + * respectively, replace + * let a := expr + * by + * mstore(, expr) + * + * In a multi-variable declaration, variables to be moved are replaced by fresh variables and then moved to memory: + * If b and d are in the map, replace + * let a, b, c, d := f() + * by + * let _1, _2, _3, _4 := f() + * mstore(, _4) + * mstore(, _2) + * let c := _3 + * let a := _1 + * + * Assignments to single variables are replaced by mstore's: + * If a is in the map, replace + * a := expr + * by + * mstore(, expr) + * + * Assignments to multiple variables are split up similarly to multi-variable declarations: + * If b and d are in the map, replace + * a, b, c, d := f() + * by + * let _1, _2, _3, _4 := f() + * mstore(, _4) + * mstore(, _2) + * c := _3 + * a := _1 + * + * Replace all references to a variable ``a`` in the map by ``mload()``. + * + * If a visited function has arguments or return parameters that are contained in the map, + * the entire function is skipped (no local variables in the function will be moved at all). + * + * Prerequisite: Disambiguator, ForLoopInitRewriter, FunctionHoister. + */ +class StackToMemoryMover: ASTModifier +{ +public: + /** + * Runs the stack to memory mover. + * @param _reservedMemory Is the amount of previously reserved memory, + * i.e. the lowest memory offset to which variables can be moved. + * @param _memorySlots A map from variables to a slot in memory. Based on the slot a unique offset in the memory range + * between _reservedMemory and _reservedMemory + 32 * _numRequiredSlots is calculated for each + * variable. + * @param _numRequiredSlots The number of slots required in total. The maximum value that may occur in @a _memorySlots. + */ + static void run( + OptimiserStepContext& _context, + u256 _reservedMemory, + std::map> const& _memorySlots, + uint64_t _numRequiredSlots, + Block& _block + ); + using ASTModifier::operator(); + + void operator()(FunctionDefinition& _functionDefinition) override; + void operator()(Block& _block) override; + void visit(Expression& _expression) override; +private: + StackToMemoryMover( + OptimiserStepContext& _context, + u256 _reservedMemory, + std::map> const& _memorySlots, + uint64_t _numRequiredSlots + ); + + /// @returns a YulString containing the memory offset to be assigned to @a _variable as number literal. + YulString memoryOffset(YulString _variable); + + OptimiserStepContext& m_context; + u256 m_reservedMemory; + std::map> const& m_memorySlots; + uint64_t m_numRequiredSlots = 0; + NameDispenser& m_nameDispenser; + std::map const* m_currentFunctionMemorySlots = nullptr; +}; + +} \ No newline at end of file diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index a12ecd194..11249c23d 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -49,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +74,7 @@ #include #include +#include using namespace std; using namespace solidity; @@ -121,6 +126,12 @@ void OptimiserSuite::run( { yulAssert(_meter, ""); ConstantOptimiser{*dialect, *_meter}(ast); + if (dialect->providesObjectAccess()) + StackLimitEvader::run(suite.m_context, _object, CompilabilityChecker{ + _dialect, + _object, + _optimizeStackAllocation + }.unreachableVariables); } else if (dynamic_cast(&_dialect)) { @@ -180,11 +191,14 @@ map> const& OptimiserSuite::allSteps() LiteralRematerialiser, LoadResolver, LoopInvariantCodeMotion, + NameSimplifier, RedundantAssignEliminator, + ReasoningBasedSimplifier, Rematerialiser, SSAReverser, SSATransform, StructuralSimplifier, + UnusedFunctionParameterPruner, UnusedPruner, VarDeclInitializer >(); @@ -216,11 +230,14 @@ map const& OptimiserSuite::stepNameToAbbreviationMap() {LiteralRematerialiser::name, 'T'}, {LoadResolver::name, 'L'}, {LoopInvariantCodeMotion::name, 'M'}, + {NameSimplifier::name, 'N'}, + {ReasoningBasedSimplifier::name, 'R'}, {RedundantAssignEliminator::name, 'r'}, {Rematerialiser::name, 'm'}, {SSAReverser::name, 'V'}, {SSATransform::name, 'a'}, {StructuralSimplifier::name, 't'}, + {UnusedFunctionParameterPruner::name, 'p'}, {UnusedPruner::name, 'u'}, {VarDeclInitializer::name, 'd'}, }; @@ -260,6 +277,7 @@ void OptimiserSuite::validateSequence(string const& _stepAbbreviations) insideLoop = false; break; default: + { yulAssert( string(NonStepAbbreviations).find(abbreviation) == string::npos, "Unhandled syntactic element in the abbreviation sequence" @@ -269,6 +287,14 @@ void OptimiserSuite::validateSequence(string const& _stepAbbreviations) OptimizerException, "'"s + abbreviation + "' is not a valid step abbreviation" ); + optional invalid = allSteps().at(stepAbbreviationToNameMap().at(abbreviation))->invalidInCurrentEnvironment(); + assertThrow( + !invalid.has_value(), + OptimizerException, + "'"s + abbreviation + "' is invalid in the current environment: " + *invalid + ); + + } } assertThrow(!insideLoop, OptimizerException, "Unbalanced brackets"); } diff --git a/libyul/optimiser/UnusedFunctionParameterPruner.cpp b/libyul/optimiser/UnusedFunctionParameterPruner.cpp new file mode 100644 index 000000000..d103e9c6f --- /dev/null +++ b/libyul/optimiser/UnusedFunctionParameterPruner.cpp @@ -0,0 +1,127 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * UnusedFunctionParameterPruner: Optimiser step that removes unused parameters from function + * definition. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +using namespace std; +using namespace solidity::util; +using namespace solidity::yul; +using namespace solidity::yul::unusedFunctionsCommon; + +void UnusedFunctionParameterPruner::run(OptimiserStepContext& _context, Block& _ast) +{ + map references = ReferencesCounter::countReferences(_ast); + auto used = [&](auto v) -> bool { return references.count(v.name); }; + + // Function name and a pair of boolean masks, the first corresponds to parameters and the second + // corresponds to returnVariables. + // + // For the first vector in the pair, a value `false` at index `i` indicates that the function + // argument at index `i` in `FunctionDefinition::parameters` is unused inside the function body. + // + // Similarly for the second vector in the pair, a value `false` at index `i` indicates that the + // return parameter at index `i` in `FunctionDefinition::returnVariables` is unused inside + // function body. + map, vector>> usedParametersAndReturnVariables; + + // Step 1 of UnusedFunctionParameterPruner: Find functions whose parameters (both arguments and + // return-parameters) are not used in its body. + for (auto const& statement: _ast.statements) + if (holds_alternative(statement)) + { + FunctionDefinition const& f = std::get(statement); + + if (tooSimpleToBePruned(f) || boost::algorithm::all_of(f.parameters + f.returnVariables, used)) + continue; + + usedParametersAndReturnVariables[f.name] = { + applyMap(f.parameters, used), + applyMap(f.returnVariables, used) + }; + } + + set functionNamesToFree = util::keys(usedParametersAndReturnVariables); + + // Step 2 of UnusedFunctionParameterPruner: Renames the function and replaces all references to + // the function, say `f`, by its new name, say `f_1`. + NameDisplacer replace{_context.dispenser, functionNamesToFree}; + replace(_ast); + + // Inverse-Map of the above translations. In the above example, this will store an element with + // key `f_1` and value `f`. + std::map newToOriginalNames = invertMap(replace.translations()); + + // Step 3 of UnusedFunctionParameterPruner: introduce a new function in the block with body of + // the old one. Replace the body of the old one with a function call to the new one with reduced + // parameters. + // + // For example: introduce a new 'linking' function `f` with the same the body as `f_1`, but with + // reduced parameters, i.e., `function f() -> y { y := 1 }`. Now replace the body of `f_1` with + // a call to `f`, i.e., `f_1(x) -> y { y := f() }`. + iterateReplacing(_ast.statements, [&](Statement& _s) -> optional> { + if (holds_alternative(_s)) + { + // The original function except that it has a new name (e.g., `f_1`) + FunctionDefinition& originalFunction = get(_s); + if (newToOriginalNames.count(originalFunction.name)) + { + + YulString linkingFunctionName = originalFunction.name; + YulString originalFunctionName = newToOriginalNames.at(linkingFunctionName); + pair, vector> used = + usedParametersAndReturnVariables.at(originalFunctionName); + + FunctionDefinition linkingFunction = createLinkingFunction( + originalFunction, + used, + originalFunctionName, + linkingFunctionName, + _context.dispenser + ); + + originalFunction.name = originalFunctionName; + originalFunction.parameters = + filter(originalFunction.parameters, used.first); + originalFunction.returnVariables = + filter(originalFunction.returnVariables, used.second); + + return make_vector(move(originalFunction), move(linkingFunction)); + } + } + + return nullopt; + }); +} diff --git a/libyul/optimiser/UnusedFunctionParameterPruner.h b/libyul/optimiser/UnusedFunctionParameterPruner.h new file mode 100644 index 000000000..1f62a8b08 --- /dev/null +++ b/libyul/optimiser/UnusedFunctionParameterPruner.h @@ -0,0 +1,52 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +namespace solidity::yul +{ + +/** + * UnusedFunctionParameterPruner: Optimiser step that removes unused parameters in a function. + * + * If a parameter is unused, like `c` and `y` in, `function f(a,b,c) -> x, y { x := div(a,b) }` + * + * We remove the parameter and create a new "linking" function as follows: + * + * `function f(a,b) -> x { x := div(a,b) }` + * `function f2(a,b,c) -> x, y { x := f(a,b) }` + * + * and replace all references to `f` by `f2`. + * The inliner should be run afterwards to make sure that all references to `f2` are replaced by + * `f`. + * + * Prerequisites: Disambiguator, FunctionHoister, LiteralRematerialiser + * + * The step LiteralRematerialiser is not required for correctness. It helps deal with cases such as: + * `function f(x) -> y { revert(y, y} }` where the literal `y` will be replaced by its value `0`, + * allowing us to rewrite the function. + */ +struct UnusedFunctionParameterPruner +{ + static constexpr char const* name{"UnusedFunctionParameterPruner"}; + static void run(OptimiserStepContext& _context, Block& _ast); +}; + +} diff --git a/libyul/optimiser/UnusedFunctionsCommon.h b/libyul/optimiser/UnusedFunctionsCommon.h new file mode 100644 index 000000000..aaa8180f7 --- /dev/null +++ b/libyul/optimiser/UnusedFunctionsCommon.h @@ -0,0 +1,103 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +namespace solidity::yul::unusedFunctionsCommon +{ + +template +std::vector filter(std::vector const& _vec, std::vector const& _mask) +{ + yulAssert(_vec.size() == _mask.size(), ""); + + std::vector ret; + + for (size_t i = 0; i < _mask.size(); ++i) + if (_mask[i]) + ret.push_back(_vec[i]); + + return ret; +} + +/// Returns true if applying UnusedFunctionParameterPruner is not helpful or redundant because the +/// inliner will be able to handle it anyway. +bool tooSimpleToBePruned(FunctionDefinition const& _f) +{ + return _f.body.statements.size() <= 1 && CodeSize::codeSize(_f.body) <= 1; +} + +FunctionDefinition createLinkingFunction( + FunctionDefinition const& _original, + std::pair, std::vector> const& _usedParametersAndReturns, + YulString const& _originalFunctionName, + YulString const& _linkingFunctionName, + NameDispenser& _nameDispenser +) +{ + auto generateTypedName = [&](TypedName t) + { + return TypedName{ + t.location, + _nameDispenser.newName(t.name), + t.type + }; + }; + + langutil::SourceLocation loc = _original.location; + + FunctionDefinition linkingFunction{ + loc, + _linkingFunctionName, + util::applyMap(_original.parameters, generateTypedName), + util::applyMap(_original.returnVariables, generateTypedName), + {loc, {}} // body + }; + + FunctionCall call{loc, Identifier{loc, _originalFunctionName}, {}}; + for (auto const& p: filter(linkingFunction.parameters, _usedParametersAndReturns.first)) + call.arguments.emplace_back(Identifier{loc, p.name}); + + Assignment assignment{loc, {}, nullptr}; + + for (auto const& r: filter(linkingFunction.returnVariables, _usedParametersAndReturns.second)) + assignment.variableNames.emplace_back(Identifier{loc, r.name}); + + if (assignment.variableNames.empty()) + linkingFunction.body.statements.emplace_back(ExpressionStatement{loc, std::move(call)}); + else + { + assignment.value = std::make_unique(std::move(call)); + linkingFunction.body.statements.emplace_back(std::move(assignment)); + } + + return linkingFunction; +} + +} diff --git a/scripts/build_emscripten.sh b/scripts/build_emscripten.sh index f4b0fe647..cdb07bfb4 100755 --- a/scripts/build_emscripten.sh +++ b/scripts/build_emscripten.sh @@ -35,5 +35,5 @@ else fi docker run -v $(pwd):/root/project -w /root/project \ - solbuildpackpusher/solidity-buildpack-deps@sha256:d557d015918c3cf68b0d22839bab41013f0757b651a7fef21595f89721dbebcc \ + solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c\ ./scripts/travis-emscripten/build_emscripten.sh $BUILD_DIR diff --git a/scripts/deps-ppa/static_z3.sh b/scripts/deps-ppa/static_z3.sh index c5f6d6ea4..459180924 100755 --- a/scripts/deps-ppa/static_z3.sh +++ b/scripts/deps-ppa/static_z3.sh @@ -25,9 +25,9 @@ set -ev keyid=70D110489D66E2F6 email=builds@ethereum.org packagename=libz3-static-dev -version=4.8.8 +version=4.8.9 -DISTRIBUTIONS="bionic eoan focal" +DISTRIBUTIONS="bionic focal groovy" for distribution in $DISTRIBUTIONS do @@ -80,7 +80,9 @@ Vcs-Browser: https://github.com/Z3Prover/z3 Package: libz3-static-dev Section: libdevel -Architecture: any-i386 any-amd64 +Architecture: any-amd64 +Breaks: libz3-dev +Replaces: libz3-dev Multi-Arch: same Depends: \${shlibs:Depends}, \${misc:Depends} Description: theorem prover from Microsoft Research - development files (static library) diff --git a/scripts/docker/buildpack-deps/Dockerfile.emscripten b/scripts/docker/buildpack-deps/Dockerfile.emscripten index 2d9ce401d..65dcd1fc3 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.emscripten +++ b/scripts/docker/buildpack-deps/Dockerfile.emscripten @@ -29,12 +29,12 @@ # make version=1.39.15 build # FROM emscripten/emsdk:1.39.15 AS base -LABEL version="1" +LABEL version="2" ADD emscripten.jam /usr/src RUN set -ex; \ cd /usr/src; \ - git clone https://github.com/Z3Prover/z3.git -b z3-4.8.8 --depth 1 ; \ + git clone https://github.com/Z3Prover/z3.git -b z3-4.8.9 --depth 1 ; \ cd z3; \ mkdir build; \ cd build; \ diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index c30573fe1..8ee6af57f 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM gcr.io/oss-fuzz-base/base-clang as base -LABEL version="3" +LABEL version="4" ARG DEBIAN_FRONTEND=noninteractive @@ -56,7 +56,7 @@ RUN git clone -b boost-1.69.0 https://github.com/boostorg/boost.git \ rm -rf /usr/src/boost # Z3 -RUN git clone --depth 1 -b z3-4.8.7 https://github.com/Z3Prover/z3.git \ +RUN git clone --depth 1 -b z3-4.8.9 https://github.com/Z3Prover/z3.git \ /usr/src/z3; \ cd /usr/src/z3; \ mkdir build; \ diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1804 b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1804 index b8ce7c506..65750a62d 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1804 +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1804 @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:bionic AS base -LABEL version="2" +LABEL version="3" ARG DEBIAN_FRONTEND=noninteractive diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 index 78a14651d..6614ff6e7 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:focal AS base -LABEL version="2" +LABEL version="3" ARG DEBIAN_FRONTEND=noninteractive diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang index 05429eb39..88314b5a6 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:focal AS base -LABEL version="2" +LABEL version="3" ARG DEBIAN_FRONTEND=noninteractive diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 69e452b2a..8fe1b6a28 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -188,6 +188,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): # Warning (1878): SPDX license identifier not provided in source file. .... # Warning (3420): Source file does not specify required compiler version! test_ids |= find_ids_in_cmdline_test_err(path.join(top_dir, "test", "cmdlineTests", "error_codes", "err")) + test_ids |= find_ids_in_cmdline_test_err(path.join(top_dir, "test", "cmdlineTests", "yul_unimplemented", "err")) # white list of ids which are not covered by tests white_ids = { @@ -225,7 +226,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): "3893", "3997", "4010", "4802", "4805", "4828", "4904", "4990", "5052", "5073", "5170", "5188", "5272", "5333", "5347", "5473", "5622", "6041", "6052", "6272", "6708", "6792", "6931", "7110", "7128", "7186", - "7319", "7589", "7593", "7653", "7812", "7885", "8065", "8084", "8140", + "7589", "7593", "7653", "7812", "7885", "8065", "8084", "8140", "8261", "8312", "8592", "8758", "9011", "9085", "9390", "9440", "9547", "9551", "9615", "9980" } diff --git a/scripts/install_deps.ps1 b/scripts/install_deps.ps1 new file mode 100644 index 000000000..c1301c74e --- /dev/null +++ b/scripts/install_deps.ps1 @@ -0,0 +1,18 @@ +$ErrorActionPreference = "Stop" + +# Needed for Invoke-WebRequest to work via CI. +$progressPreference = "silentlyContinue" + +New-Item -ItemType Directory -Force -Path "$PSScriptRoot\..\deps" + +Invoke-WebRequest -URI "https://github.com/Kitware/CMake/releases/download/v3.18.2/cmake-3.18.2-win64-x64.zip" -OutFile cmake.zip +tar -xf cmake.zip +mv cmake-3.18.2-win64-x64 "$PSScriptRoot\..\deps\cmake" + +Invoke-WebRequest -URI "https://dl.bintray.com/boostorg/release/1.74.0/source/boost_1_74_0.zip" -OutFile boost.zip +tar -xf boost.zip +cd boost_1_74_0 +.\bootstrap.bat +.\b2 -j4 -d0 link=static runtime-link=static variant=release threading=multi address-model=64 --with-filesystem --with-system --with-program_options --with-test --prefix="$PSScriptRoot\..\deps\boost" install +if ( -not $? ) { throw "Error building boost." } +cd .. diff --git a/scripts/install_evmone.ps1 b/scripts/install_evmone.ps1 new file mode 100644 index 000000000..ba69dab34 --- /dev/null +++ b/scripts/install_evmone.ps1 @@ -0,0 +1,9 @@ +$ErrorActionPreference = "Stop" + +# Needed for Invoke-WebRequest to work via CI. +$progressPreference = "silentlyContinue" + +Invoke-WebRequest -URI "https://github.com/ethereum/evmone/releases/download/v0.5.0/evmone-0.5.0-windows-amd64.zip" -OutFile "evmone.zip" +tar -xf evmone.zip "bin/evmone.dll" +mkdir deps +mv bin/evmone.dll deps diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index 3017692cc..ebe8c316b 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -57,7 +57,7 @@ packagename=solc static_build_distribution=focal -DISTRIBUTIONS="bionic eoan focal" +DISTRIBUTIONS="bionic focal groovy" if is_release then @@ -158,7 +158,7 @@ Vcs-Git: git://github.com/ethereum/solidity.git Vcs-Browser: https://github.com/ethereum/solidity Package: solc -Architecture: any-i386 any-amd64 +Architecture: any-amd64 Multi-Arch: same Depends: \${shlibs:Depends}, \${misc:Depends} Conflicts: libethereum (<= 1.2.9) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 8e8abf4e5..596ae1728 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -127,6 +127,8 @@ static string const g_strEVM = "evm"; static string const g_strEVM15 = "evm15"; static string const g_strEVMVersion = "evm-version"; static string const g_strEwasm = "ewasm"; +static string const g_strGeneratedSources = "generated-sources"; +static string const g_strGeneratedSourcesRuntime = "generated-sources-runtime"; static string const g_strGas = "gas"; static string const g_strHelp = "help"; static string const g_strImportAst = "import-ast"; @@ -238,6 +240,8 @@ static set const g_combinedJsonArgs g_strBinary, g_strBinaryRuntime, g_strCompactJSON, + g_strGeneratedSources, + g_strGeneratedSourcesRuntime, g_strInterface, g_strMetadata, g_strNatspecUser, @@ -1523,6 +1527,10 @@ void CommandLineInterface::handleCombinedJSON() contractData[g_strAsm] = m_compiler->assemblyJSON(contractName); if (requests.count(g_strStorageLayout) && m_compiler->compilationSuccessful()) contractData[g_strStorageLayout] = jsonCompactPrint(m_compiler->storageLayout(contractName)); + if (requests.count(g_strGeneratedSources) && m_compiler->compilationSuccessful()) + contractData[g_strGeneratedSources] = m_compiler->generatedSources(contractName, false); + if (requests.count(g_strGeneratedSourcesRuntime) && m_compiler->compilationSuccessful()) + contractData[g_strGeneratedSourcesRuntime] = m_compiler->generatedSources(contractName, true); if (requests.count(g_strSrcMap) && m_compiler->compilationSuccessful()) { auto map = m_compiler->sourceMapping(contractName); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3567f20ce..052929c09 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -79,9 +79,6 @@ set(libsolidity_sources libsolidity/SemanticTest.cpp libsolidity/SemanticTest.h libsolidity/SemVerMatcher.cpp - libsolidity/SMTChecker.cpp - libsolidity/SMTCheckerJSONTest.cpp - libsolidity/SMTCheckerJSONTest.h libsolidity/SMTCheckerTest.cpp libsolidity/SMTCheckerTest.h libsolidity/SolidityCompiler.cpp diff --git a/test/Common.cpp b/test/Common.cpp index b56cb3257..5e7059013 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -17,6 +17,7 @@ // SPDX-License-Identifier: GPL-3.0 #include +#include #include #include @@ -57,9 +58,9 @@ boost::filesystem::path testPath() return {}; } -std::string EVMOneEnvOrDefaultPath() +std::string envOrDefaultPath(std::string const& env_name, std::string const& lib_name) { - if (auto path = getenv("ETH_EVMONE")) + if (auto path = getenv(env_name.c_str())) return path; auto const searchPath = @@ -76,7 +77,7 @@ std::string EVMOneEnvOrDefaultPath() }; for (auto const& basePath: searchPath) { - fs::path p = basePath / evmoneFilename; + fs::path p = basePath / lib_name; if (fs::exists(p)) return p.string(); } @@ -92,7 +93,8 @@ CommonOptions::CommonOptions(std::string _caption): options.add_options() ("evm-version", po::value(&evmVersionString), "which evm version to use") ("testpath", po::value(&this->testPath)->default_value(solidity::test::testPath()), "path to test files") - ("evmonepath", po::value(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to evmone library") + ("vm", po::value>(&vmPaths), "path to evmc library, can be supplied multiple times.") + ("ewasm", po::bool_switch(&ewasm), "tries to automatically find an ewasm vm and enable ewasm test-execution.") ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") ("optimize", po::bool_switch(&optimize), "enables optimization") ("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") @@ -141,6 +143,33 @@ bool CommonOptions::parse(int argc, char const* const* argv) throw std::runtime_error(errorMessage.str()); } + if (vmPaths.empty()) + { + std::string evmone = envOrDefaultPath("ETH_EVMONE", evmoneFilename); + if (!evmone.empty()) + vmPaths.emplace_back(evmone); + else + { + std::cout << "Unable to find " << solidity::test::evmoneFilename + << ". Please provide the path using --vm ." << std::endl; + std::cout << "You can download it at" << std::endl; + std::cout << solidity::test::evmoneDownloadLink << std::endl; + } + } + + if (ewasm) { + std::string hera = envOrDefaultPath("ETH_HERA", heraFilename); + if (!hera.empty()) + vmPaths.emplace_back(hera); + else { + std::cout << "Unable to find " << solidity::test::heraFilename + << ". Please provide the path using --vm ." << std::endl; + std::cout << "You can download it at" << std::endl; + std::cout << solidity::test::heraDownloadLink << std::endl; + std::cout << "Ewasm tests disabled." << std::endl; + } + } + return true; } diff --git a/test/Common.h b/test/Common.h index eaad7f0ba..a665d563f 100644 --- a/test/Common.h +++ b/test/Common.h @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -31,21 +33,27 @@ namespace solidity::test #ifdef _WIN32 static constexpr auto evmoneFilename = "evmone.dll"; static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-windows-amd64.zip"; +static constexpr auto heraFilename = "hera.dll"; +static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/archive/v0.3.0.tar.gz"; #elif defined(__APPLE__) static constexpr auto evmoneFilename = "libevmone.dylib"; static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-darwin-x86_64.tar.gz"; +static constexpr auto heraFilename = "libhera.dylib"; +static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.3.0/hera-0.3.0-darwin-x86_64.tar.gz"; #else static constexpr auto evmoneFilename = "libevmone.so"; static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-linux-x86_64.tar.gz"; +static constexpr auto heraFilename = "libhera.so"; +static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.3.0/hera-0.3.0-linux-x86_64.tar.gz"; #endif - struct ConfigException : public util::Exception {}; struct CommonOptions: boost::noncopyable { - boost::filesystem::path evmonePath; + std::vector vmPaths; boost::filesystem::path testPath; + bool ewasm = false; bool optimize = false; bool enforceViaYul = false; bool disableSMT = false; @@ -64,8 +72,8 @@ struct CommonOptions: boost::noncopyable CommonOptions(std::string caption = ""); virtual ~CommonOptions() {}; -protected: +protected: boost::program_options::options_description options; private: diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 51dc83352..3b4ea2117 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -39,17 +39,18 @@ using namespace evmc::literals; evmc::VM& EVMHost::getVM(string const& _path) { - static evmc::VM theVM; - if (!theVM && !_path.empty()) + static evmc::VM NullVM{nullptr}; + static map> vms; + if (vms.count(_path) == 0) { evmc_loader_error_code errorCode = {}; auto vm = evmc::VM{evmc_load_and_configure(_path.c_str(), &errorCode)}; if (vm && errorCode == EVMC_LOADER_SUCCESS) { - if (vm.get_capabilities() & EVMC_CAPABILITY_EVM1) - theVM = std::move(vm); + if (vm.get_capabilities() & (EVMC_CAPABILITY_EVM1 | EVMC_CAPABILITY_EWASM)) + vms[_path] = make_unique(evmc::VM(move(vm))); else - cerr << "VM loaded does not support EVM1" << endl; + cerr << "VM loaded neither supports EVM1 nor EWASM" << endl; } else { @@ -59,7 +60,38 @@ evmc::VM& EVMHost::getVM(string const& _path) cerr << endl; } } - return theVM; + + if (vms.count(_path) > 0) + return *vms[_path]; + + return NullVM; +} + +bool EVMHost::checkVmPaths(vector const& _vmPaths) +{ + bool evmVmFound = false; + bool ewasmVmFound = false; + for (auto const& path: _vmPaths) + { + evmc::VM& vm = EVMHost::getVM(path.string()); + if (!vm) + return false; + + if (vm.has_capability(EVMC_CAPABILITY_EVM1)) + { + if (evmVmFound) + throw runtime_error("Multiple evm1 evmc vms defined. Please only define one evm1 evmc vm."); + evmVmFound = true; + } + + if (vm.has_capability(EVMC_CAPABILITY_EWASM)) + { + if (ewasmVmFound) + throw runtime_error("Multiple ewasm evmc vms where defined. Please only define one ewasm evmc vm."); + ewasmVmFound = true; + } + } + return evmVmFound; } EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): @@ -91,6 +123,22 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): else assertThrow(false, Exception, "Unsupported EVM version"); + tx_context.block_difficulty = evmc::uint256be{200000000}; + tx_context.block_gas_limit = 20000000; + tx_context.block_coinbase = 0x7878787878787878787878787878787878787878_address; + tx_context.tx_gas_price = evmc::uint256be{3000000000}; + tx_context.tx_origin = 0x9292929292929292929292929292929292929292_address; + // Mainnet according to EIP-155 + tx_context.chain_id = evmc::uint256be{1}; + + reset(); +} + +void EVMHost::reset() +{ + accounts.clear(); + m_currentAddress = {}; + // 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,19 +147,13 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): // roughly 22 days before the update went live. for (unsigned precompiledAddress = 1; precompiledAddress <= 8; precompiledAddress++) { - evmc::address address{}; - address.bytes[19] = precompiledAddress; + evmc::address address{precompiledAddress}; // 1wei accounts[address].balance = evmc::uint256be{1}; + // Set according to EIP-1052. + if (precompiledAddress < 5 || m_evmVersion >= langutil::EVMVersion::byzantium()) + accounts[address].codehash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470_bytes32; } - - tx_context.block_difficulty = evmc::uint256be{200000000}; - tx_context.block_gas_limit = 20000000; - tx_context.block_coinbase = 0x7878787878787878787878787878787878787878_address; - tx_context.tx_gas_price = evmc::uint256be{3000000000}; - tx_context.tx_origin = 0x9292929292929292929292929292929292929292_address; - // Mainnet according to EIP-155 - tx_context.chain_id = evmc::uint256be{1}; } void EVMHost::selfdestruct(const evmc::address& _addr, const evmc::address& _beneficiary) noexcept diff --git a/test/EVMHost.h b/test/EVMHost.h index af38426be..768c20659 100644 --- a/test/EVMHost.h +++ b/test/EVMHost.h @@ -30,6 +30,8 @@ #include +#include + namespace solidity::test { using Address = util::h160; @@ -40,14 +42,19 @@ public: using MockedHost::get_code_size; using MockedHost::get_balance; - /// Tries to dynamically load libevmone. @returns nullptr on failure. - /// The path has to be provided for the first successful run and will be ignored - /// afterwards. + /// Tries to dynamically load an evmc vm supporting evm1 or ewasm and caches the loaded VM. + /// @returns vmc::VM(nullptr) on failure. static evmc::VM& getVM(std::string const& _path = {}); - explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm = getVM()); + /// Tries to load all defined evmc vm shared libraries. + /// @param _vmPaths paths to multiple evmc shared libraries. + /// @throw Exception if multiple evm1 or multiple ewasm evmc vms where loaded. + /// @returns true, if an evmc vm was supporting evm1 loaded properly. + static bool checkVmPaths(std::vector const& _vmPaths); - void reset() { accounts.clear(); m_currentAddress = {}; } + explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm); + + void reset(); void newBlock() { tx_context.block_number++; @@ -71,6 +78,12 @@ public: static util::h256 convertFromEVMC(evmc::bytes32 const& _data); static evmc::bytes32 convertToEVMC(util::h256 const& _data); + /// @returns true, if the evmc VM has the given capability. + bool hasCapability(evmc_capabilities capability) const noexcept + { + return m_vm.has_capability(capability); + } + private: evmc::address m_currentAddress = {}; diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index 7f5dfcf74..a17f65f3c 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -29,6 +29,8 @@ #include +#include + #include #include @@ -40,27 +42,47 @@ using namespace solidity::util; using namespace solidity::test; ExecutionFramework::ExecutionFramework(): - ExecutionFramework(solidity::test::CommonOptions::get().evmVersion()) + ExecutionFramework(solidity::test::CommonOptions::get().evmVersion(), solidity::test::CommonOptions::get().vmPaths) { } -ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion): +ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion, vector const& _vmPaths): m_evmVersion(_evmVersion), m_optimiserSettings(solidity::frontend::OptimiserSettings::minimal()), m_showMessages(solidity::test::CommonOptions::get().showMessages), - m_evmHost(make_shared(m_evmVersion)) + m_vmPaths(_vmPaths) { if (solidity::test::CommonOptions::get().optimize) m_optimiserSettings = solidity::frontend::OptimiserSettings::standard(); + for (auto const& path: m_vmPaths) + if (EVMHost::getVM(path.string()).has_capability(EVMC_CAPABILITY_EWASM)) + m_supportsEwasm = true; + + selectVM(evmc_capabilities::EVMC_CAPABILITY_EVM1); +} + +void ExecutionFramework::selectVM(evmc_capabilities _cap) +{ + m_evmcHost.reset(); + for (auto const& path: m_vmPaths) + { + evmc::VM& vm = EVMHost::getVM(path.string()); + if (vm.has_capability(_cap)) + { + m_evmcHost = make_unique(m_evmVersion, vm); + break; + } + } + solAssert(m_evmcHost != nullptr, ""); reset(); } void ExecutionFramework::reset() { - m_evmHost->reset(); + m_evmcHost->reset(); for (size_t i = 0; i < 10; i++) - m_evmHost->accounts[EVMHost::convertToEVMC(account(i))].balance = + m_evmcHost->accounts[EVMHost::convertToEVMC(account(i))].balance = EVMHost::convertToEVMC(u256(1) << 100); } @@ -92,7 +114,7 @@ std::pair ExecutionFramework::compareAndCreateMessage( u256 ExecutionFramework::gasLimit() const { - return {m_evmHost->tx_context.block_gas_limit}; + return {m_evmcHost->tx_context.block_gas_limit}; } u256 ExecutionFramework::gasPrice() const @@ -100,24 +122,24 @@ u256 ExecutionFramework::gasPrice() const // here and below we use "return u256{....}" instead of just "return {....}" // to please MSVC and avoid unexpected // warning C4927 : illegal conversion; more than one user - defined conversion has been implicitly applied - return u256{EVMHost::convertFromEVMC(m_evmHost->tx_context.tx_gas_price)}; + return u256{EVMHost::convertFromEVMC(m_evmcHost->tx_context.tx_gas_price)}; } u256 ExecutionFramework::blockHash(u256 const& _number) const { return u256{EVMHost::convertFromEVMC( - m_evmHost->get_block_hash(static_cast(_number & numeric_limits::max())) + m_evmcHost->get_block_hash(static_cast(_number & numeric_limits::max())) )}; } u256 ExecutionFramework::blockNumber() const { - return m_evmHost->tx_context.block_number; + return m_evmcHost->tx_context.block_number; } void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value) { - m_evmHost->newBlock(); + m_evmcHost->newBlock(); if (m_showMessages) { @@ -147,7 +169,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 } message.gas = m_gas.convert_to(); - evmc::result result = m_evmHost->call(message); + evmc::result result = m_evmcHost->call(message); m_output = bytes(result.output_data, result.output_data + result.output_size); if (_isCreation) @@ -166,7 +188,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount) { - m_evmHost->newBlock(); + m_evmcHost->newBlock(); if (m_showMessages) { @@ -181,12 +203,12 @@ void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount) message.destination = EVMHost::convertToEVMC(_addr); message.gas = m_gas.convert_to(); - m_evmHost->call(message); + m_evmcHost->call(message); } size_t ExecutionFramework::currentTimestamp() { - return static_cast(m_evmHost->tx_context.block_timestamp); + return static_cast(m_evmcHost->tx_context.block_timestamp); } size_t ExecutionFramework::blockTimestamp(u256 _block) @@ -204,32 +226,32 @@ Address ExecutionFramework::account(size_t _idx) bool ExecutionFramework::addressHasCode(Address const& _addr) { - return m_evmHost->get_code_size(EVMHost::convertToEVMC(_addr)) != 0; + return m_evmcHost->get_code_size(EVMHost::convertToEVMC(_addr)) != 0; } size_t ExecutionFramework::numLogs() const { - return m_evmHost->recorded_logs.size(); + return m_evmcHost->recorded_logs.size(); } size_t ExecutionFramework::numLogTopics(size_t _logIdx) const { - return m_evmHost->recorded_logs.at(_logIdx).topics.size(); + return m_evmcHost->recorded_logs.at(_logIdx).topics.size(); } h256 ExecutionFramework::logTopic(size_t _logIdx, size_t _topicIdx) const { - return EVMHost::convertFromEVMC(m_evmHost->recorded_logs.at(_logIdx).topics.at(_topicIdx)); + return EVMHost::convertFromEVMC(m_evmcHost->recorded_logs.at(_logIdx).topics.at(_topicIdx)); } Address ExecutionFramework::logAddress(size_t _logIdx) const { - return EVMHost::convertFromEVMC(m_evmHost->recorded_logs.at(_logIdx).creator); + return EVMHost::convertFromEVMC(m_evmcHost->recorded_logs.at(_logIdx).creator); } bytes ExecutionFramework::logData(size_t _logIdx) const { - const auto& data = m_evmHost->recorded_logs.at(_logIdx).data; + const auto& data = m_evmcHost->recorded_logs.at(_logIdx).data; // TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(), // but reference type like string_view would be preferable. return {data.begin(), data.end()}; @@ -237,13 +259,13 @@ bytes ExecutionFramework::logData(size_t _logIdx) const u256 ExecutionFramework::balanceAt(Address const& _addr) { - return u256(EVMHost::convertFromEVMC(m_evmHost->get_balance(EVMHost::convertToEVMC(_addr)))); + return u256(EVMHost::convertFromEVMC(m_evmcHost->get_balance(EVMHost::convertToEVMC(_addr)))); } bool ExecutionFramework::storageEmpty(Address const& _addr) { - const auto it = m_evmHost->accounts.find(EVMHost::convertToEVMC(_addr)); - if (it != m_evmHost->accounts.end()) + const auto it = m_evmcHost->accounts.find(EVMHost::convertToEVMC(_addr)); + if (it != m_evmcHost->accounts.end()) { for (auto const& entry: it->second.storage) if (!(entry.second.value == evmc::bytes32{})) diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 69fd93a1c..9b01d9a91 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include #include @@ -39,8 +40,6 @@ namespace solidity::test { -class EVMHost; - using rational = boost::rational; /// An Ethereum address: 20 bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes. @@ -55,7 +54,7 @@ class ExecutionFramework public: ExecutionFramework(); - explicit ExecutionFramework(langutil::EVMVersion _evmVersion); + ExecutionFramework(langutil::EVMVersion _evmVersion, std::vector const& _vmPaths); virtual ~ExecutionFramework() = default; virtual bytes const& compileAndRunWithoutCheck( @@ -255,6 +254,7 @@ private: } protected: + void selectVM(evmc_capabilities _cap = evmc_capabilities::EVMC_CAPABILITY_EVM1); void reset(); void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0); @@ -279,7 +279,10 @@ protected: solidity::frontend::RevertStrings m_revertStrings = solidity::frontend::RevertStrings::Default; solidity::frontend::OptimiserSettings m_optimiserSettings = solidity::frontend::OptimiserSettings::minimal(); bool m_showMessages = false; - std::shared_ptr m_evmHost; + bool m_supportsEwasm = false; + std::unique_ptr m_evmcHost; + + std::vector m_vmPaths; bool m_transactionSuccessful = true; Address m_sender = account(0); diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index 7ecc8de5e..2daf716aa 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/test/TestCase.h b/test/TestCase.h index 1815409fe..65cc4eeb6 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -39,6 +39,7 @@ public: { std::string filename; langutil::EVMVersion evmVersion; + std::vector vmPaths; bool enforceCompileViaYul; }; diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 8f065a7bb..81aae19ab 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -72,7 +71,7 @@ int registerTests( { int numTestsAdded = 0; fs::path fullpath = _basepath / _path; - TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), _enforceViaYul}; + TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), solidity::test::CommonOptions::get().vmPaths, _enforceViaYul}; if (fs::is_directory(fullpath)) { test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string()); @@ -156,14 +155,19 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) initializeOptions(); - bool disableSemantics = !solidity::test::EVMHost::getVM(solidity::test::CommonOptions::get().evmonePath.string()); - if (disableSemantics) + bool disableSemantics = true; + try { - cout << "Unable to find " << solidity::test::evmoneFilename << ". Please provide the path using -- --evmonepath ." << endl; - cout << "You can download it at" << endl; - cout << solidity::test::evmoneDownloadLink << endl; - cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; + disableSemantics = !solidity::test::EVMHost::checkVmPaths(solidity::test::CommonOptions::get().vmPaths); } + catch (std::runtime_error const& _exception) + { + cerr << "Error: " << _exception.what() << endl; + exit(1); + } + if (disableSemantics) + cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; + // Include the interactive tests in the automatic tests as well for (auto const& ts: g_interactiveTestsuites) { @@ -201,9 +205,6 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) removeTestSuite(suite); } - if (solidity::test::CommonOptions::get().disableSMT) - removeTestSuite("SMTChecker"); - return nullptr; } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 448ba5a6e..abb7ab5ba 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -124,6 +124,8 @@ function test_solc_behaviour() sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path" sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path" + sed -i.bak -e 's/\(Unimplemented feature error: .* in \).*$/\1FILENAME REMOVED/' "$stderr_path" + sed -i.bak -e 's/"version": "[^"]*"/"version": "VERSION REMOVED"/' "$stdout_path" # Remove trailing empty lines. Needs a line break to make OSX sed happy. sed -i.bak -e '1{/^$/d }' "$stderr_path" diff --git a/test/cmdlineTests/combined_json_generated_sources/args b/test/cmdlineTests/combined_json_generated_sources/args new file mode 100644 index 000000000..425ca0a0b --- /dev/null +++ b/test/cmdlineTests/combined_json_generated_sources/args @@ -0,0 +1 @@ +--combined-json generated-sources,generated-sources-runtime --pretty-json diff --git a/test/cmdlineTests/combined_json_generated_sources/err b/test/cmdlineTests/combined_json_generated_sources/err new file mode 100644 index 000000000..c6113508b --- /dev/null +++ b/test/cmdlineTests/combined_json_generated_sources/err @@ -0,0 +1,5 @@ +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. +--> combined_json_generated_sources/input.sol + +Warning: Source file does not specify required compiler version! +--> combined_json_generated_sources/input.sol diff --git a/test/cmdlineTests/combined_json_generated_sources/exit b/test/cmdlineTests/combined_json_generated_sources/exit new file mode 100644 index 000000000..c22708346 --- /dev/null +++ b/test/cmdlineTests/combined_json_generated_sources/exit @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/test/cmdlineTests/combined_json_generated_sources/input.sol b/test/cmdlineTests/combined_json_generated_sources/input.sol new file mode 100644 index 000000000..7fce7aa65 --- /dev/null +++ b/test/cmdlineTests/combined_json_generated_sources/input.sol @@ -0,0 +1,5 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint[] calldata) pure external {} +} \ No newline at end of file diff --git a/test/cmdlineTests/combined_json_generated_sources/output b/test/cmdlineTests/combined_json_generated_sources/output new file mode 100644 index 000000000..d93c81871 --- /dev/null +++ b/test/cmdlineTests/combined_json_generated_sources/output @@ -0,0 +1,735 @@ +{ + "contracts": + { + "combined_json_generated_sources/input.sol:C": + { + "generated-sources": [], + "generated-sources-runtime": + [ + { + "ast": + { + "nodeType": "YulBlock", + "src": "0:823:1", + "statements": + [ + { + "body": + { + "nodeType": "YulBlock", + "src": "114:277:1", + "statements": + [ + { + "body": + { + "nodeType": "YulBlock", + "src": "163:16:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "172:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "175:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "165:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "165:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "165:12:1" + } + ] + }, + "condition": + { + "arguments": + [ + { + "arguments": + [ + { + "arguments": + [ + { + "name": "offset", + "nodeType": "YulIdentifier", + "src": "142:6:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "150:4:1", + "type": "", + "value": "0x1f" + } + ], + "functionName": + { + "name": "add", + "nodeType": "YulIdentifier", + "src": "138:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "138:17:1" + }, + { + "name": "end", + "nodeType": "YulIdentifier", + "src": "157:3:1" + } + ], + "functionName": + { + "name": "slt", + "nodeType": "YulIdentifier", + "src": "134:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "134:27:1" + } + ], + "functionName": + { + "name": "iszero", + "nodeType": "YulIdentifier", + "src": "127:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "127:35:1" + }, + "nodeType": "YulIf", + "src": "124:2:1" + }, + { + "nodeType": "YulAssignment", + "src": "188:30:1", + "value": + { + "arguments": + [ + { + "name": "offset", + "nodeType": "YulIdentifier", + "src": "211:6:1" + } + ], + "functionName": + { + "name": "calldataload", + "nodeType": "YulIdentifier", + "src": "198:12:1" + }, + "nodeType": "YulFunctionCall", + "src": "198:20:1" + }, + "variableNames": + [ + { + "name": "length", + "nodeType": "YulIdentifier", + "src": "188:6:1" + } + ] + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "261:16:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "270:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "273:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "263:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "263:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "263:12:1" + } + ] + }, + "condition": + { + "arguments": + [ + { + "name": "length", + "nodeType": "YulIdentifier", + "src": "233:6:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "241:18:1", + "type": "", + "value": "0xffffffffffffffff" + } + ], + "functionName": + { + "name": "gt", + "nodeType": "YulIdentifier", + "src": "230:2:1" + }, + "nodeType": "YulFunctionCall", + "src": "230:30:1" + }, + "nodeType": "YulIf", + "src": "227:2:1" + }, + { + "nodeType": "YulAssignment", + "src": "286:29:1", + "value": + { + "arguments": + [ + { + "name": "offset", + "nodeType": "YulIdentifier", + "src": "302:6:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "310:4:1", + "type": "", + "value": "0x20" + } + ], + "functionName": + { + "name": "add", + "nodeType": "YulIdentifier", + "src": "298:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "298:17:1" + }, + "variableNames": + [ + { + "name": "arrayPos", + "nodeType": "YulIdentifier", + "src": "286:8:1" + } + ] + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "369:16:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "378:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "381:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "371:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "371:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "371:12:1" + } + ] + }, + "condition": + { + "arguments": + [ + { + "arguments": + [ + { + "name": "arrayPos", + "nodeType": "YulIdentifier", + "src": "334:8:1" + }, + { + "arguments": + [ + { + "name": "length", + "nodeType": "YulIdentifier", + "src": "348:6:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "356:4:1", + "type": "", + "value": "0x20" + } + ], + "functionName": + { + "name": "mul", + "nodeType": "YulIdentifier", + "src": "344:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "344:17:1" + } + ], + "functionName": + { + "name": "add", + "nodeType": "YulIdentifier", + "src": "330:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "330:32:1" + }, + { + "name": "end", + "nodeType": "YulIdentifier", + "src": "364:3:1" + } + ], + "functionName": + { + "name": "gt", + "nodeType": "YulIdentifier", + "src": "327:2:1" + }, + "nodeType": "YulFunctionCall", + "src": "327:41:1" + }, + "nodeType": "YulIf", + "src": "324:2:1" + } + ] + }, + "name": "abi_decode_t_array$_t_uint256_$dyn_calldata_ptr", + "nodeType": "YulFunctionDefinition", + "parameters": + [ + { + "name": "offset", + "nodeType": "YulTypedName", + "src": "81:6:1", + "type": "" + }, + { + "name": "end", + "nodeType": "YulTypedName", + "src": "89:3:1", + "type": "" + } + ], + "returnVariables": + [ + { + "name": "arrayPos", + "nodeType": "YulTypedName", + "src": "97:8:1", + "type": "" + }, + { + "name": "length", + "nodeType": "YulTypedName", + "src": "107:6:1", + "type": "" + } + ], + "src": "24:367:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "498:322:1", + "statements": + [ + { + "body": + { + "nodeType": "YulBlock", + "src": "544:16:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "553:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "556:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "546:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "546:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "546:12:1" + } + ] + }, + "condition": + { + "arguments": + [ + { + "arguments": + [ + { + "name": "dataEnd", + "nodeType": "YulIdentifier", + "src": "519:7:1" + }, + { + "name": "headStart", + "nodeType": "YulIdentifier", + "src": "528:9:1" + } + ], + "functionName": + { + "name": "sub", + "nodeType": "YulIdentifier", + "src": "515:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "515:23:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "540:2:1", + "type": "", + "value": "32" + } + ], + "functionName": + { + "name": "slt", + "nodeType": "YulIdentifier", + "src": "511:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "511:32:1" + }, + "nodeType": "YulIf", + "src": "508:2:1" + }, + { + "nodeType": "YulBlock", + "src": "570:243:1", + "statements": + [ + { + "nodeType": "YulVariableDeclaration", + "src": "584:45:1", + "value": + { + "arguments": + [ + { + "arguments": + [ + { + "name": "headStart", + "nodeType": "YulIdentifier", + "src": "615:9:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "626:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "add", + "nodeType": "YulIdentifier", + "src": "611:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "611:17:1" + } + ], + "functionName": + { + "name": "calldataload", + "nodeType": "YulIdentifier", + "src": "598:12:1" + }, + "nodeType": "YulFunctionCall", + "src": "598:31:1" + }, + "variables": + [ + { + "name": "offset", + "nodeType": "YulTypedName", + "src": "588:6:1", + "type": "" + } + ] + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "676:16:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "685:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "688:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "678:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "678:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "678:12:1" + } + ] + }, + "condition": + { + "arguments": + [ + { + "name": "offset", + "nodeType": "YulIdentifier", + "src": "648:6:1" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "656:18:1", + "type": "", + "value": "0xffffffffffffffff" + } + ], + "functionName": + { + "name": "gt", + "nodeType": "YulIdentifier", + "src": "645:2:1" + }, + "nodeType": "YulFunctionCall", + "src": "645:30:1" + }, + "nodeType": "YulIf", + "src": "642:2:1" + }, + { + "nodeType": "YulAssignment", + "src": "705:98:1", + "value": + { + "arguments": + [ + { + "arguments": + [ + { + "name": "headStart", + "nodeType": "YulIdentifier", + "src": "775:9:1" + }, + { + "name": "offset", + "nodeType": "YulIdentifier", + "src": "786:6:1" + } + ], + "functionName": + { + "name": "add", + "nodeType": "YulIdentifier", + "src": "771:3:1" + }, + "nodeType": "YulFunctionCall", + "src": "771:22:1" + }, + { + "name": "dataEnd", + "nodeType": "YulIdentifier", + "src": "795:7:1" + } + ], + "functionName": + { + "name": "abi_decode_t_array$_t_uint256_$dyn_calldata_ptr", + "nodeType": "YulIdentifier", + "src": "723:47:1" + }, + "nodeType": "YulFunctionCall", + "src": "723:80:1" + }, + "variableNames": + [ + { + "name": "value0", + "nodeType": "YulIdentifier", + "src": "705:6:1" + }, + { + "name": "value1", + "nodeType": "YulIdentifier", + "src": "713:6:1" + } + ] + } + ] + } + ] + }, + "name": "abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr", + "nodeType": "YulFunctionDefinition", + "parameters": + [ + { + "name": "headStart", + "nodeType": "YulTypedName", + "src": "460:9:1", + "type": "" + }, + { + "name": "dataEnd", + "nodeType": "YulTypedName", + "src": "471:7:1", + "type": "" + } + ], + "returnVariables": + [ + { + "name": "value0", + "nodeType": "YulTypedName", + "src": "483:6:1", + "type": "" + }, + { + "name": "value1", + "nodeType": "YulTypedName", + "src": "491:6:1", + "type": "" + } + ], + "src": "397:423:1" + } + ] + }, + "contents": "{\n\n // uint256[]\n function abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(offset, end) -> arrayPos, length {\n if iszero(slt(add(offset, 0x1f), end)) { revert(0, 0) }\n length := calldataload(offset)\n if gt(length, 0xffffffffffffffff) { revert(0, 0) }\n arrayPos := add(offset, 0x20)\n if gt(add(arrayPos, mul(length, 0x20)), end) { revert(0, 0) }\n }\n\n function abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr(headStart, dataEnd) -> value0, value1 {\n if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }\n\n {\n let offset := calldataload(add(headStart, 0))\n if gt(offset, 0xffffffffffffffff) { revert(0, 0) }\n value0, value1 := abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(add(headStart, offset), dataEnd)\n }\n\n }\n\n}\n", + "id": 1, + "language": "Yul", + "name": "#utility.yul" + } + ] + } + }, + "version": "VERSION REMOVED" +} diff --git a/test/cmdlineTests/evm_to_wasm_break/output b/test/cmdlineTests/evm_to_wasm_break/output index ddeb04529..ecb9a9ce3 100644 --- a/test/cmdlineTests/evm_to_wasm_break/output +++ b/test/cmdlineTests/evm_to_wasm_break/output @@ -31,9 +31,10 @@ object "object" { 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))))) + let _3 := i64.or(_1, _1) + let _4:i32 := i32.eqz(i32.eqz(i64.eqz(i64.or(_3, i64.or(_1, _2))))) for { } - i32.eqz(_3) + i32.eqz(_4) { 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 @@ -42,13 +43,10 @@ object "object" { 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 } + let _5, _6, _7, _8 := iszero_170_789(_1, _1, _1, lt_172(x_4, x_5, x_6, x_7, _1, _1, _1, 10)) + if i32.eqz(i64.eqz(i64.or(i64.or(_5, _6), i64.or(_7, _8)))) { break } + if i32.eqz(i64.eqz(i64.or(_3, i64.or(_1, eq(x_4, x_5, x_6, x_7, _1, _1, _1, 2))))) { break } + if i32.eqz(i64.eqz(i64.or(_3, i64.or(_1, eq(x_4, x_5, x_6, x_7, _1, _1, _1, 4))))) { continue } } sstore(_1, _1, _1, _1, x_4, x_5, x_6, x_7) } @@ -69,11 +67,11 @@ object "object" { let r1_1, carry_2 := add_carry(x1, y1, carry_1) r1 := r1_1 } - function iszero(x1, x2, x3, x4) -> r1, r2, r3, r4 + function iszero_170_789(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 + function eq(x1, x2, x3, x4, y1, y2, y3, y4) -> r4 { if i64.eq(x1, y1) { @@ -89,7 +87,7 @@ object "object" { 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 + function lt_172(x1, x2, x3, x4, y1, y2, y3, y4) -> z4 { let z:i32 := false switch cmp(x1, y1) @@ -154,7 +152,7 @@ object "object" { Binary representation: -0061736d0100000001480a60000060017e017e60027e7e017f60037e7e7e017e60047e7e7e7e017e60087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60057f7e7e7e7e0060027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003060406020604010101070505030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020ac3080dde02030a7e017f147e02404200210002402000200020002000100921012300210223012103230221040b20012105200221062003210720042108420121092000200084200020098484504545210a02400340200a45450d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f201084201120128484504504400c030b024020052006200720082000200020004202100621132300211423012115230221160b2013201484201520168484504504400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a8484504504400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2901037e0240200020017c2105200520027c21032005200054200320055472ad21040b2004240020030b6c010b7e0240200320077c210c200c42007c210b024020022006200c200354200b200c5472ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2401047e0240200020018420022003848450ad21070b20052400200624012007240220040b3901047e0240200020045104402001200551044020022006510440200320075104404201210b0b0b0b0b0b20092400200a2401200b240220080b2701027f024002402000200154210320034101460440417f210205200020015221020b0b0b20020b960102047e047f02404100210c0240200020041007210d200d41004604400240200120051007210e200e41004604400240200220061007210f200f41004604402003200754210c05200f41014604404100210c054101210c0b0b0b05200e41014604404100210c054101210c0b0b0b05200d41014604404100210c054101210c0b0b0b200cad210b0b20092400200a2401200b240220080b7601087e024042002000200184200284520440000b42002003422088520440000b41002003a7412010014100290000100c2108410041086a290000100c2109410041106a290000100c210a410041186a290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3200024020002001100c370000200041086a2002100c370000200041106a2003100c370000200041186a2004100c3700000b0b2300024041002000200120022003100d41202004200520062007100d4100412010000b0b +0061736d0100000001480a60000060017e017e60027e7e017f60037e7e7e017e60047e7e7e7e017e60087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60057f7e7e7e7e0060027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003060406020604010101070505030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020af0070da302030b7e017f087e02404200210002402000200020002000100921012300210223012103230221040b20012105200221062003210720042108420121092000200084210a200a200020098484504545210b02400340200b45450d01024002402000200020002005200620072008200020002000420a10081005210c2300210d2301210e2302210f0b200c200d84200e200f8484504504400c030b200a20002005200620072008200020002000420210068484504504400c030b200a20002005200620072008200020002000420410068484504504400c010b0b024020052006200720082000200020002009100421102300211123012112230221130b201021052011210620122107201321080c000b0b20002000200020002005200620072008100e0b0b2901037e0240200020017c2105200520027c21032005200054200320055472ad21040b2004240020030b6c010b7e0240200320077c210c200c42007c210b024020022006200c200354200b200c5472ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2401047e0240200020018420022003848450ad21070b20052400200624012007240220040b2d01017e024020002004510440200120055104402002200651044020032007510440420121080b0b0b0b0b20080b2701027f024002402000200154210320034101460440417f210205200020015221020b0b0b20020b8a0102017e047f0240410021090240200020041007210a200a41004604400240200120051007210b200b41004604400240200220061007210c200c41004604402003200754210905200c41014604404100210905410121090b0b0b05200b41014604404100210905410121090b0b0b05200a41014604404100210905410121090b0b0b2009ad21080b20080b7601087e024042002000200184200284520440000b42002003422088520440000b41002003a7412010014100290000100c2108410041086a290000100c2109410041106a290000100c210a410041186a290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3200024020002001100c370000200041086a2002100c370000200041106a2003100c370000200041186a2004100c3700000b0b2300024041002000200120022003100d41202004200520062007100d4100412010000b0b Text representation: (module @@ -177,23 +175,12 @@ Text representation: (local $x_6 i64) (local $x_7 i64) (local $_2 i64) - (local $_3 i32) - (local $_4 i64) + (local $_3 i64) + (local $_4 i32) (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) @@ -212,46 +199,26 @@ Text representation: (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 (i32.eqz (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_1) (local.get $_1)) (i64.or (local.get $_1) (local.get $_2))))))) + (local.set $_3 (i64.or (local.get $_1) (local.get $_1))) + (local.set $_4 (i32.eqz (i32.eqz (i64.eqz (i64.or (local.get $_3) (i64.or (local.get $_1) (local.get $_2))))))) (block $label__3 (loop $label__5 - (br_if $label__3 (i32.eqz (i32.eqz (local.get $_3)))) + (br_if $label__3 (i32.eqz (i32.eqz (local.get $_4)))) (block $label__4 (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)) + (local.set $_5 (call $iszero_170_789 (local.get $_1) (local.get $_1) (local.get $_1) (call $lt_172 (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 $_6 (global.get $global_)) + (local.set $_7 (global.get $global__1)) + (local.set $_8 (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 (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_8) (local.get $_9)) (i64.or (local.get $_10) (local.get $_11))))) (then + (if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_5) (local.get $_6)) (i64.or (local.get $_7) (local.get $_8))))) (then (br $label__3) )) - (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 (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_12) (local.get $_13)) (i64.or (local.get $_14) (local.get $_15))))) (then + (if (i32.eqz (i64.eqz (i64.or (local.get $_3) (i64.or (local.get $_1) (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)))))) (then (br $label__3) )) - (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 (i32.eqz (i64.eqz (i64.or (i64.or (local.get $_16) (local.get $_17)) (i64.or (local.get $_18) (local.get $_19))))) (then + (if (i32.eqz (i64.eqz (i64.or (local.get $_3) (i64.or (local.get $_1) (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)))))) (then (br $label__4) )) @@ -343,7 +310,7 @@ Text representation: (local.get $r1) ) -(func $iszero +(func $iszero_170_789 (param $x1 i64) (param $x2 i64) (param $x3 i64) @@ -373,9 +340,6 @@ Text representation: (param $y3 i64) (param $y4 i64) (result i64) - (local $r1 i64) - (local $r2 i64) - (local $r3 i64) (local $r4 i64) (block $label__9 (if (i64.eq (local.get $x1) (local.get $y1)) (then @@ -389,10 +353,7 @@ Text representation: )) ) - (global.set $global_ (local.get $r2)) - (global.set $global__1 (local.get $r3)) - (global.set $global__2 (local.get $r4)) - (local.get $r1) + (local.get $r4) ) (func $cmp @@ -416,7 +377,7 @@ Text representation: (local.get $r) ) -(func $lt +(func $lt_172 (param $x1 i64) (param $x2 i64) (param $x3 i64) @@ -426,9 +387,6 @@ Text representation: (param $y3 i64) (param $y4 i64) (result i64) - (local $z1 i64) - (local $z2 i64) - (local $z3 i64) (local $z4 i64) (local $z i32) (local $condition_12 i32) @@ -476,10 +434,7 @@ Text representation: (local.set $z4 (i64.extend_i32_u (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) + (local.get $z4) ) (func $calldataload diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output index fd372367a..6af2128e1 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output @@ -9,7 +9,7 @@ Optimized IR: object "C_6" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } let _1 := datasize("C_6_deployed") codecopy(0, dataoffset("C_6_deployed"), _1) @@ -19,7 +19,7 @@ object "C_6" { object "C_6_deployed" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) revert(0, 0) } } @@ -37,7 +37,7 @@ Optimized IR: object "D_9" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } let _1 := datasize("D_9_deployed") codecopy(0, dataoffset("D_9_deployed"), _1) @@ -47,7 +47,7 @@ object "D_9" { object "D_9_deployed" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) revert(0, 0) } } diff --git a/test/cmdlineTests/ir_compiler_subobjects/output b/test/cmdlineTests/ir_compiler_subobjects/output index 6b5f8e677..888f1216b 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/output +++ b/test/cmdlineTests/ir_compiler_subobjects/output @@ -9,7 +9,7 @@ Optimized IR: object "C_2" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } let _1 := datasize("C_2_deployed") codecopy(0, dataoffset("C_2_deployed"), _1) @@ -19,7 +19,7 @@ object "C_2" { object "C_2_deployed" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) revert(0, 0) } } @@ -37,7 +37,7 @@ Optimized IR: object "D_13" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } let _1 := datasize("D_13_deployed") codecopy(0, dataoffset("D_13_deployed"), _1) @@ -47,20 +47,21 @@ object "D_13" { object "D_13_deployed" { code { { - mstore(64, 128) + let _1 := memoryguard(0x80) + mstore(64, _1) if iszero(lt(calldatasize(), 4)) { - let _1 := 0 - if eq(0x26121ff0, shr(224, calldataload(_1))) + let _2 := 0 + if eq(0x26121ff0, shr(224, calldataload(_2))) { - if callvalue() { revert(_1, _1) } - if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } - let _2 := datasize("C_2") - let _3 := add(128, _2) - if or(gt(_3, 0xffffffffffffffff), lt(_3, 128)) { revert(_1, _1) } - datacopy(128, dataoffset("C_2"), _2) - pop(create(_1, 128, _2)) - return(allocateMemory(_1), _1) + if callvalue() { revert(_2, _2) } + if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } + let _3 := datasize("C_2") + let _4 := add(_1, _3) + if or(gt(_4, 0xffffffffffffffff), lt(_4, _1)) { invalid() } + datacopy(_1, dataoffset("C_2"), _3) + pop(create(_2, _1, sub(_4, _1))) + return(allocateMemory(_2), _2) } } revert(0, 0) @@ -69,14 +70,14 @@ object "D_13" { { memPtr := mload(64) let newFreePtr := add(memPtr, size) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } mstore(64, newFreePtr) } } object "C_2" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } let _1 := datasize("C_2_deployed") codecopy(0, dataoffset("C_2_deployed"), _1) @@ -86,7 +87,7 @@ object "D_13" { object "C_2_deployed" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) revert(0, 0) } } diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/args b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/args new file mode 100644 index 000000000..cae21e720 --- /dev/null +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/args @@ -0,0 +1 @@ +--ir-optimized --optimize \ No newline at end of file diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol new file mode 100644 index 000000000..6dd033f13 --- /dev/null +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/input.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0.0; + +contract D { + constructor() { assembly {}} + function f() public pure {} +} diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output new file mode 100644 index 000000000..7d2430a73 --- /dev/null +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output @@ -0,0 +1,40 @@ +Optimized IR: +/******************************************************* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *******************************************************/ + +object "D_11" { + code { + { + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("D_11_deployed") + codecopy(0, dataoffset("D_11_deployed"), _1) + return(0, _1) + } + } + object "D_11_deployed" { + code { + { + let _1 := memoryguard(0x80) + mstore(64, _1) + if iszero(lt(calldatasize(), 4)) + { + let _2 := 0 + if eq(0x26121ff0, shr(224, calldataload(_2))) + { + if callvalue() { revert(_2, _2) } + if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) } + if gt(_1, 0xffffffffffffffff) { invalid() } + mstore(64, _1) + return(_1, _2) + } + } + revert(0, 0) + } + } + } +} diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/args b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/args new file mode 100644 index 000000000..cae21e720 --- /dev/null +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/args @@ -0,0 +1 @@ +--ir-optimized --optimize \ No newline at end of file diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol new file mode 100644 index 000000000..caef2b75e --- /dev/null +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/input.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0.0; + +contract D { + function f() public pure { + assembly {} + } +} diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output new file mode 100644 index 000000000..25d7edfb2 --- /dev/null +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output @@ -0,0 +1,38 @@ +Optimized IR: +/******************************************************* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *******************************************************/ + +object "D_7" { + code { + { + mstore(64, memoryguard(0x80)) + if callvalue() { revert(0, 0) } + let _1 := datasize("D_7_deployed") + codecopy(0, dataoffset("D_7_deployed"), _1) + return(0, _1) + } + } + object "D_7_deployed" { + code { + { + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + mstore(64, 128) + return(128, _1) + } + } + revert(0, 0) + } + } + } +} diff --git a/test/cmdlineTests/name_simplifier/args b/test/cmdlineTests/name_simplifier/args new file mode 100644 index 000000000..8539e69f5 --- /dev/null +++ b/test/cmdlineTests/name_simplifier/args @@ -0,0 +1 @@ +--optimize --ir-optimized --metadata-hash none diff --git a/test/cmdlineTests/name_simplifier/input.sol b/test/cmdlineTests/name_simplifier/input.sol new file mode 100644 index 000000000..b1ca2565a --- /dev/null +++ b/test/cmdlineTests/name_simplifier/input.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; +pragma experimental ABIEncoderV2; + +// The point of this test is to check that the +// AST IDs are removed from the optimized IR +// so that they do not have a big effect on the +// optimizer if it has a bug that makes it +// depen on the actual identifiers. + +struct S { uint x; } +struct T { uint[2] y; } + +contract C { + S[2] values; + T t; + + function sumArray(S[] memory _s) public returns (uint, string memory) { + values[0].x = _s[0].x; + t.y[0] = _s[1].x; + return (t.y[0], "longstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstring"); + } +} diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output new file mode 100644 index 000000000..ac94685a3 --- /dev/null +++ b/test/cmdlineTests/name_simplifier/output @@ -0,0 +1,137 @@ +Optimized IR: +/******************************************************* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *******************************************************/ + +object "C_56" { + code { + { + mstore(64, memoryguard(0x80)) + if callvalue() { revert(0, 0) } + let _1 := datasize("C_56_deployed") + codecopy(0, dataoffset("C_56_deployed"), _1) + return(0, _1) + } + } + object "C_56_deployed" { + code { + { + mstore(64, memoryguard(0x80)) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0xf8eddcc6, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + let _2 := 32 + if slt(add(calldatasize(), not(3)), _2) { revert(_1, _1) } + let offset := calldataload(4) + let _3 := 0xffffffffffffffff + if gt(offset, _3) { revert(_1, _1) } + if iszero(slt(add(offset, 35), calldatasize())) { revert(_1, _1) } + let length := calldataload(add(4, offset)) + if gt(length, _3) { invalid() } + let _4 := mul(length, _2) + let dst := allocateMemory(add(_4, _2)) + let dst_1 := dst + mstore(dst, length) + dst := add(dst, _2) + let src := add(offset, 36) + if gt(add(add(offset, _4), 36), calldatasize()) { revert(_1, _1) } + let i := _1 + for { } lt(i, length) { i := add(i, 1) } + { + mstore(dst, abi_decode_t_struct$_S(src, calldatasize())) + dst := add(dst, _2) + src := add(src, _2) + } + let ret, ret_1 := fun_sumArray_55(dst_1) + let memPos := allocateMemory(_1) + return(memPos, sub(abi_encode_uint256_t_string(memPos, ret, ret_1), memPos)) + } + } + revert(0, 0) + } + function abi_decode_t_struct$_S(headStart, end) -> value + { + if slt(sub(end, headStart), 0x20) { revert(value, value) } + let memPtr := mload(64) + let newFreePtr := add(memPtr, 0x20) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } + mstore(64, newFreePtr) + value := memPtr + mstore(memPtr, calldataload(headStart)) + } + function abi_encode_uint256_t_string(headStart, value0, value1) -> tail + { + mstore(headStart, value0) + let _1 := 32 + mstore(add(headStart, _1), 64) + let length := mload(value1) + mstore(add(headStart, 64), length) + let i := tail + for { } lt(i, length) { i := add(i, _1) } + { + mstore(add(add(headStart, i), 96), mload(add(add(value1, i), _1))) + } + if gt(i, length) + { + mstore(add(add(headStart, length), 96), tail) + } + tail := add(add(headStart, and(add(length, 31), not(31))), 96) + } + function allocateMemory(size) -> memPtr + { + memPtr := mload(64) + let newFreePtr := add(memPtr, size) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } + mstore(64, newFreePtr) + } + function convert_t_stringliteral_6490_to_t_string() -> converted + { + let memPtr := mload(64) + let newFreePtr := add(memPtr, 160) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } + mstore(64, newFreePtr) + converted := memPtr + mstore(memPtr, 100) + mstore(add(memPtr, 32), "longstringlongstringlongstringlo") + mstore(add(memPtr, 64), "ngstringlongstringlongstringlong") + mstore(add(memPtr, 96), "stringlongstringlongstringlongst") + mstore(add(memPtr, 128), "ring") + } + function extract_from_storage_value_dynamict_uint256(slot_value, offset) -> value + { + value := shr(mul(offset, 8), slot_value) + } + function fun_sumArray_55(vloc__s_19_mpos) -> vloc, vloc__24_mpos + { + let _1 := mload(vloc__s_19_mpos) + if iszero(lt(vloc, _1)) { invalid() } + let _2 := mload(mload(add(add(vloc__s_19_mpos, mul(vloc, 32)), 32))) + let _3, _4 := storage_array_index_access$_t_struct$_S_storage(vloc, vloc) + sstore(_3, _2) + if iszero(lt(0x01, _1)) { invalid() } + let _5 := mload(mload(add(vloc__s_19_mpos, 64))) + if iszero(lt(vloc, 0x02)) { invalid() } + let slot := add(0x02, vloc) + let _6 := sload(slot) + let shiftBits := mul(vloc, 8) + let mask := shl(shiftBits, not(0)) + sstore(slot, or(and(_6, not(mask)), and(shl(shiftBits, _5), mask))) + let _7, _8 := storage_array_index_access$_t_struct$_S_storage(0x02, vloc) + vloc := extract_from_storage_value_dynamict_uint256(sload(_7), _8) + vloc__24_mpos := convert_t_stringliteral_6490_to_t_string() + } + function storage_array_index_access$_t_struct$_S_storage(array, index) -> slot, offset + { + if iszero(lt(index, 0x02)) { invalid() } + slot := add(array, index) + offset := offset + } + } + } +} diff --git a/test/cmdlineTests/optimizer_array_sload/output b/test/cmdlineTests/optimizer_array_sload/output index ea4ae03ff..c7f8a9d7d 100644 --- a/test/cmdlineTests/optimizer_array_sload/output +++ b/test/cmdlineTests/optimizer_array_sload/output @@ -9,7 +9,7 @@ Optimized IR: object "Arraysum_33" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } let _1 := datasize("Arraysum_33_deployed") codecopy(0, dataoffset("Arraysum_33_deployed"), _1) @@ -19,7 +19,7 @@ object "Arraysum_33" { object "Arraysum_33_deployed" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if iszero(lt(calldatasize(), 4)) { let _1 := 0 @@ -33,19 +33,22 @@ object "Arraysum_33" { for { } lt(vloc_i, _2) { - vloc_i := increment_t_uint256(vloc_i) + if gt(vloc_i, not(1)) { invalid() } + vloc_i := add(vloc_i, 1) } { - let _3, _4 := storage_array_index_access_t_array$_t_uint256_$dyn_storage(_1, vloc_i) - vloc_sum := checked_add_t_uint256(vloc_sum, extract_from_storage_value_dynamict_uint256(sload(_3), _4)) + mstore(_1, _1) + let _3 := sload(add(keccak256(_1, 0x20), vloc_i)) + if gt(vloc_sum, not(_3)) { invalid() } + vloc_sum := add(vloc_sum, _3) } let memPos := allocateMemory(_1) - return(memPos, sub(abi_encode_tuple_t_uint256__to_t_uint256__fromStack(memPos, _1), memPos)) + return(memPos, sub(abi_encode_uint(memPos, _1), memPos)) } } revert(0, 0) } - function abi_encode_tuple_t_uint256__to_t_uint256__fromStack(headStart, value0) -> tail + function abi_encode_uint(headStart, value0) -> tail { tail := add(headStart, 32) mstore(headStart, value0) @@ -54,30 +57,9 @@ object "Arraysum_33" { { memPtr := mload(64) let newFreePtr := add(memPtr, size) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } mstore(64, newFreePtr) } - function checked_add_t_uint256(x, y) -> sum - { - if gt(x, not(y)) { revert(sum, sum) } - sum := add(x, y) - } - function extract_from_storage_value_dynamict_uint256(slot_value, offset) -> value - { - value := shr(mul(offset, 8), slot_value) - } - function increment_t_uint256(value) -> ret - { - if gt(value, not(1)) { revert(ret, ret) } - ret := add(value, 1) - } - function storage_array_index_access_t_array$_t_uint256_$dyn_storage(array, index) -> slot, offset - { - if iszero(lt(index, sload(array))) { invalid() } - mstore(slot, array) - slot := add(keccak256(slot, 0x20), index) - offset := offset - } } } } diff --git a/test/cmdlineTests/output_selection_all_A1/output.json b/test/cmdlineTests/output_selection_all_A1/output.json index 1e4a0b11f..9f0cfa596 100644 --- a/test/cmdlineTests/output_selection_all_A1/output.json +++ b/test/cmdlineTests/output_selection_all_A1/output.json @@ -1,4 +1,4 @@ -{"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","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","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","errorCode":"3420","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","errorCode":"2018","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); } } diff --git a/test/cmdlineTests/output_selection_all_A2/output.json b/test/cmdlineTests/output_selection_all_A2/output.json index 5b0b55bbf..ae00e3485 100644 --- a/test/cmdlineTests/output_selection_all_A2/output.json +++ b/test/cmdlineTests/output_selection_all_A2/output.json @@ -1,4 +1,4 @@ -{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","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","errorCode":"3420","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","errorCode":"2018","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); } } diff --git a/test/cmdlineTests/output_selection_all_star/output.json b/test/cmdlineTests/output_selection_all_star/output.json index d885876d9..64653e63f 100644 --- a/test/cmdlineTests/output_selection_all_star/output.json +++ b/test/cmdlineTests/output_selection_all_star/output.json @@ -1,4 +1,4 @@ -{"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","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","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","errorCode":"3420","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","errorCode":"2018","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); } } diff --git a/test/cmdlineTests/output_selection_single_A1/output.json b/test/cmdlineTests/output_selection_single_A1/output.json index b32b519dd..e29036fde 100644 --- a/test/cmdlineTests/output_selection_single_A1/output.json +++ b/test/cmdlineTests/output_selection_single_A1/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","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},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_B1/output.json b/test/cmdlineTests/output_selection_single_B1/output.json index aeb29d7ae..9915b12ab 100644 --- a/test/cmdlineTests/output_selection_single_B1/output.json +++ b/test/cmdlineTests/output_selection_single_B1/output.json @@ -1,4 +1,4 @@ -{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","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","errorCode":"2018","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); } } ^------------------------------------------^ diff --git a/test/cmdlineTests/output_selection_single_all/output.json b/test/cmdlineTests/output_selection_single_all/output.json index 07b1a5453..f98685b2e 100644 --- a/test/cmdlineTests/output_selection_single_all/output.json +++ b/test/cmdlineTests/output_selection_single_all/output.json @@ -1,2 +1,2 @@ -{"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"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","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},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/standard_eWasm_requested/output.json b/test/cmdlineTests/standard_eWasm_requested/output.json index 7b2af14bf..a3885d128 100644 --- a/test/cmdlineTests/standard_eWasm_requested/output.json +++ b/test/cmdlineTests/standard_eWasm_requested/output.json @@ -6,9 +6,6 @@ (import \"ethereum\" \"finish\" (func $eth.finish (param 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) @@ -18,7 +15,6 @@ (local $z1 i64) (local $z2 i64) (local $z3 i64) - (local $z4 i64) (local $_3 i64) (block $label_ (local.set $_1 (i64.const 0)) @@ -32,18 +28,14 @@ (i64.store (i32.add (local.get $r) (i32.const 16)) (local.get $_2)) (i64.store (i32.add (local.get $r) (i32.const 24)) (call $endian_swap (i64.const 128))) (call $eth.getCallValue (i32.const 0)) - (block - (local.set $z1 (call $mload_internal (i32.const 0))) - (local.set $z2 (global.get $global_)) - (local.set $z3 (global.get $global__1)) - (local.set $z4 (global.get $global__2)) - - ) - (if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (local.get $z4))))) (then - (call $eth.revert (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))))) + (local.set $z1 (call $endian_swap (i64.load (i32.const 0)))) + (local.set $z2 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 8))))) + (local.set $z3 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 16))))) + (if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 24)))))))) (then + (call $revert (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)))) (local.set $_3 (datasize \"C_2_deployed\")) - (call $eth.codeCopy (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\")) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))) - (call $eth.finish (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))) + (call $codecopy (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\") (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3)) + (call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3)) ) ) @@ -54,7 +46,7 @@ (param $x4 i64) (result i32) (local $v i32) - (block $label__3 + (block $label__1 (if (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3))) (then (unreachable))) (if (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32))) (then @@ -73,7 +65,7 @@ (result i32) (local $r i32) (local $p i32) - (block $label__4 + (block $label__2 (local.set $p (call $u256_to_i32 (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4))) (local.set $r (i32.add (local.get $p) (i32.const 64))) (if (i32.lt_u (local.get $r) (local.get $p)) (then @@ -83,11 +75,29 @@ (local.get $r) ) +(func $codecopy + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (param $z1 i64) + (param $z2 i64) + (param $z3 i64) + (param $z4 i64) + (block $label__3 + (call $eth.codeCopy (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)) (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4))) + ) +) + (func $endian_swap_16 (param $x i64) (result i64) (local $y i64) - (block $label__5 + (block $label__4 (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)))) ) @@ -99,7 +109,7 @@ (result i64) (local $y i64) (local $hi i64) - (block $label__6 + (block $label__5 (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))))) @@ -112,7 +122,7 @@ (result i64) (local $y i64) (local $hi i64) - (block $label__7 + (block $label__6 (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))))) @@ -120,24 +130,32 @@ (local.get $y) ) -(func $mload_internal - (param $pos i32) - (result i64) - (local $z1 i64) - (local $z2 i64) - (local $z3 i64) - (local $z4 i64) - (block $label__8 - (local.set $z1 (call $endian_swap (i64.load (local.get $pos)))) - (local.set $z2 (call $endian_swap (i64.load (i32.add (local.get $pos) (i32.const 8))))) - (local.set $z3 (call $endian_swap (i64.load (i32.add (local.get $pos) (i32.const 16))))) - (local.set $z4 (call $endian_swap (i64.load (i32.add (local.get $pos) (i32.const 24))))) - +(func $return + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (block $label__7 + (call $eth.finish (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) + ) +) + +(func $revert + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (block $label__8 + (call $eth.revert (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4))) ) - (global.set $global_ (local.get $z2)) - (global.set $global__1 (local.get $z3)) - (global.set $global__2 (local.get $z4)) - (local.get $z1) ) ) diff --git a/test/cmdlineTests/standard_generatedSources/input.json b/test/cmdlineTests/standard_generatedSources/input.json new file mode 100644 index 000000000..75537c4fb --- /dev/null +++ b/test/cmdlineTests/standard_generatedSources/input.json @@ -0,0 +1,20 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma experimental ABIEncoderV2; contract A { function f(uint[] memory) public view returns (uint256) { } }" + } + }, + "settings": { + "evmVersion": "petersburg", + "outputSelection": { + "*": { + "A": [ + "evm.bytecode.object", + "evm.deployedBytecode.generatedSources", + "evm.bytecode.generatedSources" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_generatedSources/output.json b/test/cmdlineTests/standard_generatedSources/output.json new file mode 100644 index 000000000..d6c9d3f36 --- /dev/null +++ b/test/cmdlineTests/standard_generatedSources/output.json @@ -0,0 +1,81 @@ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:2555:1","statements":[{"body":{"nodeType":"YulBlock","src":"101:684:1","statements":[{"body":{"nodeType":"YulBlock","src":"150:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"159:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"162:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"152:6:1"},"nodeType":"YulFunctionCall","src":"152:12:1"},"nodeType":"YulExpressionStatement","src":"152:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"129:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"137:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"125:3:1"},"nodeType":"YulFunctionCall","src":"125:17:1"},{"name":"end","nodeType":"YulIdentifier","src":"144:3:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"121:3:1"},"nodeType":"YulFunctionCall","src":"121:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"114:6:1"},"nodeType":"YulFunctionCall","src":"114:35:1"},"nodeType":"YulIf","src":"111:2:1"},{"nodeType":"YulVariableDeclaration","src":"175:34:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"202:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"189:12:1"},"nodeType":"YulFunctionCall","src":"189:20:1"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"179:6:1","type":""}]},{"nodeType":"YulAssignment","src":"218:89:1","value":{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"299:6:1"}],"functionName":{"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"242:56:1"},"nodeType":"YulFunctionCall","src":"242:64:1"}],"functionName":{"name":"allocateMemory","nodeType":"YulIdentifier","src":"227:14:1"},"nodeType":"YulFunctionCall","src":"227:80:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"218:5:1"}]},{"nodeType":"YulVariableDeclaration","src":"316:16:1","value":{"name":"array","nodeType":"YulIdentifier","src":"327:5:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"320:3:1","type":""}]},{"expression":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"348:5:1"},{"name":"length","nodeType":"YulIdentifier","src":"355:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"341:6:1"},"nodeType":"YulFunctionCall","src":"341:21:1"},"nodeType":"YulExpressionStatement","src":"341:21:1"},{"nodeType":"YulAssignment","src":"363:27:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"377:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"385:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"373:3:1"},"nodeType":"YulFunctionCall","src":"373:17:1"},"variableNames":[{"name":"offset","nodeType":"YulIdentifier","src":"363:6:1"}]},{"nodeType":"YulAssignment","src":"391:21:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"402:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"407:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"398:3:1"},"nodeType":"YulFunctionCall","src":"398:14:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"391:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"452:17:1","value":{"name":"offset","nodeType":"YulIdentifier","src":"463:6:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"456:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"518:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"527:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"530:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"520:6:1"},"nodeType":"YulFunctionCall","src":"520:12:1"},"nodeType":"YulExpressionStatement","src":"520:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"488:3:1"},{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"497:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"505:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"493:3:1"},"nodeType":"YulFunctionCall","src":"493:17:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"484:3:1"},"nodeType":"YulFunctionCall","src":"484:27:1"},{"name":"end","nodeType":"YulIdentifier","src":"513:3:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"481:2:1"},"nodeType":"YulFunctionCall","src":"481:36:1"},"nodeType":"YulIf","src":"478:2:1"},{"body":{"nodeType":"YulBlock","src":"603:176:1","statements":[{"nodeType":"YulVariableDeclaration","src":"617:21:1","value":{"name":"src","nodeType":"YulIdentifier","src":"635:3:1"},"variables":[{"name":"elementPos","nodeType":"YulTypedName","src":"621:10:1","type":""}]},{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"658:3:1"},{"arguments":[{"name":"elementPos","nodeType":"YulIdentifier","src":"684:10:1"},{"name":"end","nodeType":"YulIdentifier","src":"696:3:1"}],"functionName":{"name":"abi_decode_t_uint256","nodeType":"YulIdentifier","src":"663:20:1"},"nodeType":"YulFunctionCall","src":"663:37:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"651:6:1"},"nodeType":"YulFunctionCall","src":"651:50:1"},"nodeType":"YulExpressionStatement","src":"651:50:1"},{"nodeType":"YulAssignment","src":"714:21:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"725:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"730:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"721:3:1"},"nodeType":"YulFunctionCall","src":"721:14:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"714:3:1"}]},{"nodeType":"YulAssignment","src":"748:21:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"759:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"764:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"755:3:1"},"nodeType":"YulFunctionCall","src":"755:14:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"748:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"565:1:1"},{"name":"length","nodeType":"YulIdentifier","src":"568:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"562:2:1"},"nodeType":"YulFunctionCall","src":"562:13:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"576:18:1","statements":[{"nodeType":"YulAssignment","src":"578:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"587:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"590:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"583:3:1"},"nodeType":"YulFunctionCall","src":"583:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"578:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"547:14:1","statements":[{"nodeType":"YulVariableDeclaration","src":"549:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"558:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"553:1:1","type":""}]}]},"src":"543:236:1"}]},"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"79:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"87:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"95:5:1","type":""}],"src":"24:761:1"},{"body":{"nodeType":"YulBlock","src":"843:87:1","statements":[{"nodeType":"YulAssignment","src":"853:29:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"875:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"862:12:1"},"nodeType":"YulFunctionCall","src":"862:20:1"},"variableNames":[{"name":"value","nodeType":"YulIdentifier","src":"853:5:1"}]},{"expression":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"918:5:1"}],"functionName":{"name":"validator_revert_t_uint256","nodeType":"YulIdentifier","src":"891:26:1"},"nodeType":"YulFunctionCall","src":"891:33:1"},"nodeType":"YulExpressionStatement","src":"891:33:1"}]},"name":"abi_decode_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"821:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"829:3:1","type":""}],"returnVariables":[{"name":"value","nodeType":"YulTypedName","src":"837:5:1","type":""}],"src":"791:139:1"},{"body":{"nodeType":"YulBlock","src":"1027:312:1","statements":[{"body":{"nodeType":"YulBlock","src":"1073:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1082:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1085:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1075:6:1"},"nodeType":"YulFunctionCall","src":"1075:12:1"},"nodeType":"YulExpressionStatement","src":"1075:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"1048:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"1057:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"1044:3:1"},"nodeType":"YulFunctionCall","src":"1044:23:1"},{"kind":"number","nodeType":"YulLiteral","src":"1069:2:1","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"1040:3:1"},"nodeType":"YulFunctionCall","src":"1040:32:1"},"nodeType":"YulIf","src":"1037:2:1"},{"nodeType":"YulBlock","src":"1099:233:1","statements":[{"nodeType":"YulVariableDeclaration","src":"1113:45:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1144:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1155:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1140:3:1"},"nodeType":"YulFunctionCall","src":"1140:17:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1127:12:1"},"nodeType":"YulFunctionCall","src":"1127:31:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"1117:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1205:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1214:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1217:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1207:6:1"},"nodeType":"YulFunctionCall","src":"1207:12:1"},"nodeType":"YulExpressionStatement","src":"1207:12:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1177:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1185:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1174:2:1"},"nodeType":"YulFunctionCall","src":"1174:30:1"},"nodeType":"YulIf","src":"1171:2:1"},{"nodeType":"YulAssignment","src":"1234:88:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1294:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"1305:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1290:3:1"},"nodeType":"YulFunctionCall","src":"1290:22:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1314:7:1"}],"functionName":{"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"1244:45:1"},"nodeType":"YulFunctionCall","src":"1244:78:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1234:6:1"}]}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"997:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"1008:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"1020:6:1","type":""}],"src":"936:403:1"},{"body":{"nodeType":"YulBlock","src":"1410:53:1","statements":[{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1427:3:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1450:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"1432:17:1"},"nodeType":"YulFunctionCall","src":"1432:24:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1420:6:1"},"nodeType":"YulFunctionCall","src":"1420:37:1"},"nodeType":"YulExpressionStatement","src":"1420:37:1"}]},"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1398:5:1","type":""},{"name":"pos","nodeType":"YulTypedName","src":"1405:3:1","type":""}],"src":"1345:118:1"},{"body":{"nodeType":"YulBlock","src":"1567:124:1","statements":[{"nodeType":"YulAssignment","src":"1577:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1589:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1600:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1585:3:1"},"nodeType":"YulFunctionCall","src":"1585:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1577:4:1"}]},{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"1657:6:1"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1670:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1681:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1666:3:1"},"nodeType":"YulFunctionCall","src":"1666:17:1"}],"functionName":{"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulIdentifier","src":"1613:43:1"},"nodeType":"YulFunctionCall","src":"1613:71:1"},"nodeType":"YulExpressionStatement","src":"1613:71:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1539:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1551:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1562:4:1","type":""}],"src":"1469:222:1"},{"body":{"nodeType":"YulBlock","src":"1737:238:1","statements":[{"nodeType":"YulAssignment","src":"1747:19:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1763:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1757:5:1"},"nodeType":"YulFunctionCall","src":"1757:9:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1747:6:1"}]},{"nodeType":"YulVariableDeclaration","src":"1775:35:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1797:6:1"},{"name":"size","nodeType":"YulIdentifier","src":"1805:4:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1793:3:1"},"nodeType":"YulFunctionCall","src":"1793:17:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"1779:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1921:17:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error","nodeType":"YulIdentifier","src":"1923:11:1"},"nodeType":"YulFunctionCall","src":"1923:13:1"},"nodeType":"YulExpressionStatement","src":"1923:13:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1864:10:1"},{"kind":"number","nodeType":"YulLiteral","src":"1876:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1861:2:1"},"nodeType":"YulFunctionCall","src":"1861:34:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1900:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"1912:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1897:2:1"},"nodeType":"YulFunctionCall","src":"1897:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"1858:2:1"},"nodeType":"YulFunctionCall","src":"1858:62:1"},"nodeType":"YulIf","src":"1855:2:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1954:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1958:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1947:6:1"},"nodeType":"YulFunctionCall","src":"1947:22:1"},"nodeType":"YulExpressionStatement","src":"1947:22:1"}]},"name":"allocateMemory","nodeType":"YulFunctionDefinition","parameters":[{"name":"size","nodeType":"YulTypedName","src":"1721:4:1","type":""}],"returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"1730:6:1","type":""}],"src":"1697:278:1"},{"body":{"nodeType":"YulBlock","src":"2063:224:1","statements":[{"body":{"nodeType":"YulBlock","src":"2168:17:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error","nodeType":"YulIdentifier","src":"2170:11:1"},"nodeType":"YulFunctionCall","src":"2170:13:1"},"nodeType":"YulExpressionStatement","src":"2170:13:1"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2140:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2148:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"2137:2:1"},"nodeType":"YulFunctionCall","src":"2137:30:1"},"nodeType":"YulIf","src":"2134:2:1"},{"nodeType":"YulAssignment","src":"2195:25:1","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2207:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2215:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"2203:3:1"},"nodeType":"YulFunctionCall","src":"2203:17:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"2195:4:1"}]},{"nodeType":"YulAssignment","src":"2257:23:1","value":{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"2269:4:1"},{"kind":"number","nodeType":"YulLiteral","src":"2275:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2265:3:1"},"nodeType":"YulFunctionCall","src":"2265:15:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"2257:4:1"}]}]},"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"length","nodeType":"YulTypedName","src":"2047:6:1","type":""}],"returnVariables":[{"name":"size","nodeType":"YulTypedName","src":"2058:4:1","type":""}],"src":"1981:306:1"},{"body":{"nodeType":"YulBlock","src":"2338:32:1","statements":[{"nodeType":"YulAssignment","src":"2348:16:1","value":{"name":"value","nodeType":"YulIdentifier","src":"2359:5:1"},"variableNames":[{"name":"cleaned","nodeType":"YulIdentifier","src":"2348:7:1"}]}]},"name":"cleanup_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"2320:5:1","type":""}],"returnVariables":[{"name":"cleaned","nodeType":"YulTypedName","src":"2330:7:1","type":""}],"src":"2293:77:1"},{"body":{"nodeType":"YulBlock","src":"2399:25:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"invalid","nodeType":"YulIdentifier","src":"2409:7:1"},"nodeType":"YulFunctionCall","src":"2409:9:1"},"nodeType":"YulExpressionStatement","src":"2409:9:1"}]},"name":"panic_error","nodeType":"YulFunctionDefinition","src":"2376:48:1"},{"body":{"nodeType":"YulBlock","src":"2473:79:1","statements":[{"body":{"nodeType":"YulBlock","src":"2530:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"2539:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2542:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"2532:6:1"},"nodeType":"YulFunctionCall","src":"2532:12:1"},"nodeType":"YulExpressionStatement","src":"2532:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"2496:5:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"2521:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"2503:17:1"},"nodeType":"YulFunctionCall","src":"2503:24:1"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"2493:2:1"},"nodeType":"YulFunctionCall","src":"2493:35:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"2486:6:1"},"nodeType":"YulFunctionCall","src":"2486:43:1"},"nodeType":"YulIf","src":"2483:2:1"}]},"name":"validator_revert_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"2466:5:1","type":""}],"src":"2430:122:1"}]},"contents":"{ + + // uint256[] + function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset, end) -> array { + if iszero(slt(add(offset, 0x1f), end)) { revert(0, 0) } + let length := calldataload(offset) + array := allocateMemory(array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length)) + let dst := array + mstore(array, length) offset := add(offset, 0x20) dst := add(dst, 0x20) // might update offset and dst + let src := offset + if gt(add(src, mul(length, 0x20)), end) { revert(0, 0) } + for { let i := 0 } lt(i, length) { i := add(i, 1) } + { + let elementPos := src + mstore(dst, abi_decode_t_uint256(elementPos, end)) + dst := add(dst, 0x20) + src := add(src, 0x20) + } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + function abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert(0, 0) } + + { + let offset := calldataload(add(headStart, 0)) + if gt(offset, 0xffffffffffffffff) { revert(0, 0) } + value0 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) { + mstore(pos, cleanup_t_uint256(value)) + } + + function abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed(headStart , value0) -> tail { + tail := add(headStart, 32) + + abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0)) + + } + + function allocateMemory(size) -> memPtr { + memPtr := mload(64) + let newFreePtr := add(memPtr, size) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } + mstore(64, newFreePtr) + } + + function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error() } + + size := mul(length, 0x20) + + // add length slot + size := add(size, 0x20) + + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function panic_error() { + invalid() + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + +} +","id":1,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"70:74:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83:59;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;130:7;83:59;;;:::o;24:761:1:-;;144:3;137:4;129:6;125:17;121:27;111:2;;162:1;159;152:12;111:2;202:6;189:20;227:80;242:64;299:6;242:64;:::i;:::-;227:80;:::i;:::-;218:89;;327:5;355:6;348:5;341:21;385:4;377:6;373:17;363:27;;407:4;402:3;398:14;391:21;;463:6;513:3;505:4;497:6;493:17;488:3;484:27;481:36;478:2;;;530:1;527;520:12;478:2;558:1;543:236;568:6;565:1;562:13;543:236;;;635:3;663:37;696:3;684:10;663:37;:::i;:::-;658:3;651:50;730:4;725:3;721:14;714:21;;764:4;759:3;755:14;748:21;;603:176;590:1;587;583:9;578:14;;543:236;;;547:14;101:684;;;;;;;:::o;791:139::-;;875:6;862:20;853:29;;891:33;918:5;891:33;:::i;:::-;843:87;;;;:::o;936:403::-;;1069:2;1057:9;1048:7;1044:23;1040:32;1037:2;;;1085:1;1082;1075:12;1037:2;1155:1;1144:9;1140:17;1127:31;1185:18;1177:6;1174:30;1171:2;;;1217:1;1214;1207:12;1171:2;1244:78;1314:7;1305:6;1294:9;1290:22;1244:78;:::i;:::-;1234:88;;1099:233;1027:312;;;;:::o;1345:118::-;1432:24;1450:5;1432:24;:::i;:::-;1427:3;1420:37;1410:53;;:::o;1469:222::-;;1600:2;1589:9;1585:18;1577:26;;1613:71;1681:1;1670:9;1666:17;1657:6;1613:71;:::i;:::-;1567:124;;;;:::o;1697:278::-;;1763:2;1757:9;1747:19;;1805:4;1797:6;1793:17;1912:6;1900:10;1897:22;1876:18;1864:10;1861:34;1858:62;1855:2;;;1923:13;;:::i;:::-;1855:2;1958:10;1954:2;1947:22;1737:238;;;;:::o;1981:306::-;;2148:18;2140:6;2137:30;2134:2;;;2170:13;;:::i;:::-;2134:2;2215:4;2207:6;2203:17;2195:25;;2275:4;2269;2265:15;2257:23;;2063:224;;;:::o;2293:77::-;;2359:5;2348:16;;2338:32;;;:::o;2376:48::-;2409:9;2430:122;2503:24;2521:5;2503:24;:::i;:::-;2496:5;2493:35;2483:2;;2542:1;2539;2532:12;2483:2;2473:79;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","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_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json index 48376adc5..2f935a12d 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":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"generatedSources":[],"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","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/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index ba3cb8b2a..6e3a00778 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -7,7 +7,7 @@ object \"C_6\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_6() codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) @@ -17,7 +17,7 @@ object \"C_6\" { } object \"C_6_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { let selector := shift_right_224_unsigned(calldataload(0)) @@ -44,11 +44,13 @@ object \"C_6\" { { memPtr := mload(64) let newFreePtr := add(memPtr, size) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } function fun_f_5() { } + function panic_error() + { invalid() } function shift_right_224_unsigned(value) -> newValue { newValue := shr(224, value) } } diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index f63075090..47cec2625 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -8,7 +8,7 @@ object \"C_6\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_6() @@ -24,7 +24,7 @@ object \"C_6\" { } object \"C_6_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { @@ -61,7 +61,7 @@ object \"C_6\" { memPtr := mload(64) let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } @@ -69,6 +69,10 @@ object \"C_6\" { } + function panic_error() { + invalid() + } + function shift_right_224_unsigned(value) -> newValue { newValue := diff --git a/test/cmdlineTests/standard_optimizer_generatedSources/input.json b/test/cmdlineTests/standard_optimizer_generatedSources/input.json new file mode 100644 index 000000000..f3682dd28 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_generatedSources/input.json @@ -0,0 +1,21 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma experimental ABIEncoderV2; contract A { function f(uint[] memory) public view returns (uint256) { } }" + } + }, + "settings": { + "evmVersion": "petersburg", + "optimizer": { "enabled": true }, + "outputSelection": { + "*": { + "A": [ + "evm.bytecode.object", + "evm.deployedBytecode.generatedSources", + "evm.bytecode.generatedSources" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_optimizer_generatedSources/output.json b/test/cmdlineTests/standard_optimizer_generatedSources/output.json new file mode 100644 index 000000000..6bb53f856 --- /dev/null +++ b/test/cmdlineTests/standard_optimizer_generatedSources/output.json @@ -0,0 +1,43 @@ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:1458:1","statements":[{"nodeType":"YulBlock","src":"6:3:1","statements":[]},{"body":{"nodeType":"YulBlock","src":"109:918:1","statements":[{"nodeType":"YulVariableDeclaration","src":"119:12:1","value":{"kind":"number","nodeType":"YulLiteral","src":"129:2:1","type":"","value":"32"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"123:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"176:26:1","statements":[{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"185:6:1"},{"name":"value0","nodeType":"YulIdentifier","src":"193:6:1"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"178:6:1"},"nodeType":"YulFunctionCall","src":"178:22:1"},"nodeType":"YulExpressionStatement","src":"178:22:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"151:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"160:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"147:3:1"},"nodeType":"YulFunctionCall","src":"147:23:1"},{"name":"_1","nodeType":"YulIdentifier","src":"172:2:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"143:3:1"},"nodeType":"YulFunctionCall","src":"143:32:1"},"nodeType":"YulIf","src":"140:2:1"},{"nodeType":"YulVariableDeclaration","src":"211:37:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"238:9:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"225:12:1"},"nodeType":"YulFunctionCall","src":"225:23:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"215:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"257:28:1","value":{"kind":"number","nodeType":"YulLiteral","src":"267:18:1","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"261:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"312:26:1","statements":[{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"321:6:1"},{"name":"value0","nodeType":"YulIdentifier","src":"329:6:1"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"314:6:1"},"nodeType":"YulFunctionCall","src":"314:22:1"},"nodeType":"YulExpressionStatement","src":"314:22:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"300:6:1"},{"name":"_2","nodeType":"YulIdentifier","src":"308:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"297:2:1"},"nodeType":"YulFunctionCall","src":"297:14:1"},"nodeType":"YulIf","src":"294:2:1"},{"nodeType":"YulVariableDeclaration","src":"347:32:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"361:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"372:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"357:3:1"},"nodeType":"YulFunctionCall","src":"357:22:1"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"351:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"427:26:1","statements":[{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"436:6:1"},{"name":"value0","nodeType":"YulIdentifier","src":"444:6:1"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"429:6:1"},"nodeType":"YulFunctionCall","src":"429:22:1"},"nodeType":"YulExpressionStatement","src":"429:22:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"406:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"410:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"402:3:1"},"nodeType":"YulFunctionCall","src":"402:13:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"417:7:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"398:3:1"},"nodeType":"YulFunctionCall","src":"398:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"391:6:1"},"nodeType":"YulFunctionCall","src":"391:35:1"},"nodeType":"YulIf","src":"388:2:1"},{"nodeType":"YulVariableDeclaration","src":"462:30:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"489:2:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"476:12:1"},"nodeType":"YulFunctionCall","src":"476:16:1"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"466:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"519:13:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"invalid","nodeType":"YulIdentifier","src":"521:7:1"},"nodeType":"YulFunctionCall","src":"521:9:1"},"nodeType":"YulExpressionStatement","src":"521:9:1"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"507:6:1"},{"name":"_2","nodeType":"YulIdentifier","src":"515:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"504:2:1"},"nodeType":"YulFunctionCall","src":"504:14:1"},"nodeType":"YulIf","src":"501:2:1"},{"nodeType":"YulVariableDeclaration","src":"541:25:1","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"555:6:1"},{"name":"_1","nodeType":"YulIdentifier","src":"563:2:1"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"551:3:1"},"nodeType":"YulFunctionCall","src":"551:15:1"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"545:2:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"575:38:1","value":{"arguments":[{"arguments":[{"name":"_4","nodeType":"YulIdentifier","src":"605:2:1"},{"name":"_1","nodeType":"YulIdentifier","src":"609:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"601:3:1"},"nodeType":"YulFunctionCall","src":"601:11:1"}],"functionName":{"name":"allocateMemory","nodeType":"YulIdentifier","src":"586:14:1"},"nodeType":"YulFunctionCall","src":"586:27:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"579:3:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"622:16:1","value":{"name":"dst","nodeType":"YulIdentifier","src":"635:3:1"},"variables":[{"name":"dst_1","nodeType":"YulTypedName","src":"626:5:1","type":""}]},{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"654:3:1"},{"name":"length","nodeType":"YulIdentifier","src":"659:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"647:6:1"},"nodeType":"YulFunctionCall","src":"647:19:1"},"nodeType":"YulExpressionStatement","src":"647:19:1"},{"nodeType":"YulAssignment","src":"675:19:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"686:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"691:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"682:3:1"},"nodeType":"YulFunctionCall","src":"682:12:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"675:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"703:22:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"718:2:1"},{"name":"_1","nodeType":"YulIdentifier","src":"722:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"714:3:1"},"nodeType":"YulFunctionCall","src":"714:11:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"707:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"771:26:1","statements":[{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"780:6:1"},{"name":"value0","nodeType":"YulIdentifier","src":"788:6:1"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"773:6:1"},"nodeType":"YulFunctionCall","src":"773:22:1"},"nodeType":"YulExpressionStatement","src":"773:22:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"748:2:1"},{"name":"_4","nodeType":"YulIdentifier","src":"752:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"744:3:1"},"nodeType":"YulFunctionCall","src":"744:11:1"},{"name":"_1","nodeType":"YulIdentifier","src":"757:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"740:3:1"},"nodeType":"YulFunctionCall","src":"740:20:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"762:7:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"737:2:1"},"nodeType":"YulFunctionCall","src":"737:33:1"},"nodeType":"YulIf","src":"734:2:1"},{"nodeType":"YulVariableDeclaration","src":"806:15:1","value":{"name":"value0","nodeType":"YulIdentifier","src":"815:6:1"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"810:1:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"879:118:1","statements":[{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"900:3:1"},{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"918:3:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"905:12:1"},"nodeType":"YulFunctionCall","src":"905:17:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"893:6:1"},"nodeType":"YulFunctionCall","src":"893:30:1"},"nodeType":"YulExpressionStatement","src":"893:30:1"},{"nodeType":"YulAssignment","src":"936:19:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"947:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"952:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"943:3:1"},"nodeType":"YulFunctionCall","src":"943:12:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"936:3:1"}]},{"nodeType":"YulAssignment","src":"968:19:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"979:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"984:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"975:3:1"},"nodeType":"YulFunctionCall","src":"975:12:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"968:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"841:1:1"},{"name":"length","nodeType":"YulIdentifier","src":"844:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"838:2:1"},"nodeType":"YulFunctionCall","src":"838:13:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"852:18:1","statements":[{"nodeType":"YulAssignment","src":"854:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"863:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"866:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"859:3:1"},"nodeType":"YulFunctionCall","src":"859:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"854:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"834:3:1","statements":[]},"src":"830:167:1"},{"nodeType":"YulAssignment","src":"1006:15:1","value":{"name":"dst_1","nodeType":"YulIdentifier","src":"1016:5:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1006:6:1"}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"75:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"86:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"98:6:1","type":""}],"src":"14:1013:1"},{"body":{"nodeType":"YulBlock","src":"1133:76:1","statements":[{"nodeType":"YulAssignment","src":"1143:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1155:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1166:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1151:3:1"},"nodeType":"YulFunctionCall","src":"1151:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1143:4:1"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1185:9:1"},{"name":"value0","nodeType":"YulIdentifier","src":"1196:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1178:6:1"},"nodeType":"YulFunctionCall","src":"1178:25:1"},"nodeType":"YulExpressionStatement","src":"1178:25:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1102:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1113:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1124:4:1","type":""}],"src":"1032:177:1"},{"body":{"nodeType":"YulBlock","src":"1258:198:1","statements":[{"nodeType":"YulAssignment","src":"1268:19:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1284:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"1278:5:1"},"nodeType":"YulFunctionCall","src":"1278:9:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1268:6:1"}]},{"nodeType":"YulVariableDeclaration","src":"1296:35:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1318:6:1"},{"name":"size","nodeType":"YulIdentifier","src":"1326:4:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1314:3:1"},"nodeType":"YulFunctionCall","src":"1314:17:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"1300:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1406:13:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"invalid","nodeType":"YulIdentifier","src":"1408:7:1"},"nodeType":"YulFunctionCall","src":"1408:9:1"},"nodeType":"YulExpressionStatement","src":"1408:9:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1349:10:1"},{"kind":"number","nodeType":"YulLiteral","src":"1361:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1346:2:1"},"nodeType":"YulFunctionCall","src":"1346:34:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1385:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"1397:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1382:2:1"},"nodeType":"YulFunctionCall","src":"1382:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"1343:2:1"},"nodeType":"YulFunctionCall","src":"1343:62:1"},"nodeType":"YulIf","src":"1340:2:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1435:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1439:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1428:6:1"},"nodeType":"YulFunctionCall","src":"1428:22:1"},"nodeType":"YulExpressionStatement","src":"1428:22:1"}]},"name":"allocateMemory","nodeType":"YulFunctionDefinition","parameters":[{"name":"size","nodeType":"YulTypedName","src":"1238:4:1","type":""}],"returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"1247:6:1","type":""}],"src":"1214:242:1"}]},"contents":"{ + { } + function abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr(headStart, dataEnd) -> value0 + { + let _1 := 32 + if slt(sub(dataEnd, headStart), _1) { revert(value0, value0) } + let offset := calldataload(headStart) + let _2 := 0xffffffffffffffff + if gt(offset, _2) { revert(value0, value0) } + let _3 := add(headStart, offset) + if iszero(slt(add(_3, 0x1f), dataEnd)) { revert(value0, value0) } + let length := calldataload(_3) + if gt(length, _2) { invalid() } + let _4 := mul(length, _1) + let dst := allocateMemory(add(_4, _1)) + let dst_1 := dst + mstore(dst, length) + dst := add(dst, _1) + let src := add(_3, _1) + if gt(add(add(_3, _4), _1), dataEnd) { revert(value0, value0) } + let i := value0 + for { } lt(i, length) { i := add(i, 1) } + { + mstore(dst, calldataload(src)) + dst := add(dst, _1) + src := add(src, _1) + } + value0 := dst_1 + } + function abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed(headStart, value0) -> tail + { + tail := add(headStart, 32) + mstore(headStart, value0) + } + function allocateMemory(size) -> memPtr + { + memPtr := mload(64) + let newFreePtr := add(memPtr, size) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } + mstore(64, newFreePtr) + } +}","id":1,"language":"Yul","name":"#utility.yul"}],"immutableReferences":{},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"70:74:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;83:59;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;130:7:0;;83:59::o;14:1013:1:-;;129:2;172;160:9;151:7;147:23;143:32;140:2;;;193:6;185;178:22;140:2;238:9;225:23;267:18;308:2;300:6;297:14;294:2;;;329:6;321;314:22;294:2;372:6;361:9;357:22;347:32;;417:7;410:4;406:2;402:13;398:27;388:2;;444:6;436;429:22;388:2;489;476:16;515:2;507:6;504:14;501:2;;;521:9;501:2;563;555:6;551:15;541:25;;586:27;609:2;605;601:11;586:27;:::i;:::-;647:19;;;682:12;;;;714:11;;;744;;;740:20;;737:33;-1:-1:-1;734:2:1;;;788:6;780;773:22;734:2;815:6;806:15;;830:167;844:6;841:1;838:13;830:167;;;905:17;;893:30;;866:1;859:9;;;;;943:12;;;;975;;830:167;;;-1:-1:-1;1016:5:1;109:918;-1:-1:-1;;;;;;;;109:918:1:o;1032:177::-;1178:25;;;1166:2;1151:18;;1133:76::o;1214:242::-;1284:2;1278:9;1314:17;;;1361:18;1346:34;;1382:22;;;1343:62;1340:2;;;1408:9;1340:2;1435;1428:22;1258:198;;-1:-1:-1;1258:198:1:o"}}}}},"errors":[{"component":"general","errorCode":"3420","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_yul/output.json b/test/cmdlineTests/standard_yul/output.json index ac6c8f7cb..3b048f04e 100644 --- a/test/cmdlineTests/standard_yul/output.json +++ b/test/cmdlineTests/standard_yul/output.json @@ -14,7 +14,7 @@ sstore /* \"A\":0:42 */ pop -","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { +","bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { code { let x := mload(0) sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_object/output.json b/test/cmdlineTests/standard_yul_object/output.json index 946e5773b..4e770527b 100644 --- a/test/cmdlineTests/standard_yul_object/output.json +++ b/test/cmdlineTests/standard_yul_object/output.json @@ -13,7 +13,7 @@ pop stop data_4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 616263 -","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" { +","bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" { code { let x := dataoffset(\"DataName\") sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_object_name/output.json b/test/cmdlineTests/standard_yul_object_name/output.json index 58d78b3a9..e23e4a7af 100644 --- a/test/cmdlineTests/standard_yul_object_name/output.json +++ b/test/cmdlineTests/standard_yul_object_name/output.json @@ -22,7 +22,7 @@ sub_0: assembly { /* \"A\":137:149 */ revert } -","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"},"deployedBytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" { +","bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"},"deployedBytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" { code { let x := dataoffset(\"DataName\") sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/output.json b/test/cmdlineTests/standard_yul_optimiserSteps/output.json index 383ad8557..6a1ac3d40 100644 --- a/test/cmdlineTests/standard_yul_optimiserSteps/output.json +++ b/test/cmdlineTests/standard_yul_optimiserSteps/output.json @@ -13,7 +13,7 @@ /* \"A\":20:40 */ sstore pop -","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { +","bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { code { let x := mload(0) sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/standard_yul_optimized/output.json b/test/cmdlineTests/standard_yul_optimized/output.json index 532ff00d9..962d92a32 100644 --- a/test/cmdlineTests/standard_yul_optimized/output.json +++ b/test/cmdlineTests/standard_yul_optimized/output.json @@ -5,7 +5,7 @@ mload /* \"A\":20:40 */ sstore -","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { +","bytecode":{"generatedSources":[],"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { code { let x := mload(0) sstore(add(x, 0), 0) diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index 847c731e9..b37f0b44e 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -9,7 +9,7 @@ Optimized IR: object "C_6" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if callvalue() { revert(0, 0) } codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed")) return(0, datasize("C_6_deployed")) @@ -18,7 +18,7 @@ object "C_6" { object "C_6_deployed" { code { { - mstore(64, 128) + mstore(64, memoryguard(0x80)) if iszero(lt(calldatasize(), 4)) { let selector := shift_right_224_unsigned(calldataload(0)) diff --git a/test/cmdlineTests/yul_stack_opt/input.sol b/test/cmdlineTests/yul_stack_opt/input.sol index 772a6d4df..d60620ecf 100644 --- a/test/cmdlineTests/yul_stack_opt/input.sol +++ b/test/cmdlineTests/yul_stack_opt/input.sol @@ -17,6 +17,21 @@ sstore(add(a, 10), b) sstore(add(a, 11), b) sstore(add(a, 12), b) + a3 := 1 + b3 := 1 + c3 := 1 + d3 := 1 + e3 := 1 + f3 := 1 + g3 := 1 + h3 := 1 + i3 := 1 + j3 := 1 + k3 := 1 + l3 := 1 + m3 := 1 + o3 := 1 + p3 := 1 } let a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1 := fun() let a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2 := fun() diff --git a/test/cmdlineTests/yul_stack_opt/output b/test/cmdlineTests/yul_stack_opt/output index e5731f1e1..5f0cee8ea 100644 --- a/test/cmdlineTests/yul_stack_opt/output +++ b/test/cmdlineTests/yul_stack_opt/output @@ -4,12 +4,6 @@ Pretty printed source: object "object" { code { - { - let a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1 := fun() - let a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2 := fun() - sstore(a1, a2) - } - function fun() -> a3, b3, c3, d3, e3, f3, g3, h3, i3, j3, k3, l3, m3, n3, o3, p3 { let _1 := 1 sstore(_1, _1) @@ -25,84 +19,29 @@ object "object" { sstore(11, _1) sstore(12, _1) sstore(13, _1) + sstore(_1, _1) + sstore(2, _1) + sstore(3, _1) + sstore(4, _1) + sstore(5, _1) + sstore(6, _1) + sstore(7, _1) + sstore(8, _1) + sstore(9, _1) + sstore(10, _1) + sstore(11, _1) + sstore(12, _1) + sstore(13, _1) + sstore(_1, _1) } } } Binary representation: -60056032565b505050505050505050505050505050601a6032565b5050505050505050505050505050508082555050609b565b60006000600060006000600060006000600060006000600060006000600060006001808155806002558060035580600455806005558060065580600755806008558060095580600a5580600b5580600c5580600d55505b909192939495969798999a9b9c9d9e9f565b +6001808155806002558060035580600455806005558060065580600755806008558060095580600a5580600b5580600c5580600d55808155806002558060035580600455806005558060065580600755806008558060095580600a5580600b5580600c5580600d5580815550 Text representation: - /* "yul_stack_opt/input.sol":495:500 */ - tag_1 - tag_2 - jump // in -tag_1: - /* "yul_stack_opt/input.sol":425:500 */ - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - /* "yul_stack_opt/input.sol":572:577 */ - tag_3 - tag_2 - jump // in -tag_3: - /* "yul_stack_opt/input.sol":502:577 */ - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - pop - /* "yul_stack_opt/input.sol":590:592 */ - dup1 - /* "yul_stack_opt/input.sol":586:588 */ - dup3 - /* "yul_stack_opt/input.sol":579:593 */ - sstore - pop - pop - /* "yul_stack_opt/input.sol":3:423 */ - jump(tag_4) -tag_2: - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 - 0x00 /* "yul_stack_opt/input.sol":98:99 */ 0x01 dup1 @@ -180,25 +119,87 @@ tag_2: /* "yul_stack_opt/input.sol":406:416 */ 0x0d /* "yul_stack_opt/input.sol":399:420 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + dup2 + /* "yul_stack_opt/input.sol":129:141 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":151:160 */ + 0x02 + /* "yul_stack_opt/input.sol":144:164 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":174:183 */ + 0x03 + /* "yul_stack_opt/input.sol":167:187 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":197:206 */ + 0x04 + /* "yul_stack_opt/input.sol":190:210 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":220:229 */ + 0x05 + /* "yul_stack_opt/input.sol":213:233 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":243:252 */ + 0x06 + /* "yul_stack_opt/input.sol":236:256 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":266:275 */ + 0x07 + /* "yul_stack_opt/input.sol":259:279 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":289:298 */ + 0x08 + /* "yul_stack_opt/input.sol":282:302 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":312:321 */ + 0x09 + /* "yul_stack_opt/input.sol":305:325 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":335:344 */ + 0x0a + /* "yul_stack_opt/input.sol":328:348 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":358:368 */ + 0x0b + /* "yul_stack_opt/input.sol":351:372 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":382:392 */ + 0x0c + /* "yul_stack_opt/input.sol":375:396 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + /* "yul_stack_opt/input.sol":406:416 */ + 0x0d + /* "yul_stack_opt/input.sol":399:420 */ + sstore + /* "yul_stack_opt/input.sol":98:99 */ + dup1 + dup2 + /* "yul_stack_opt/input.sol":729:743 */ sstore pop - /* "yul_stack_opt/input.sol":85:423 */ -tag_5: - swap1 - swap2 - swap3 - swap4 - swap5 - swap6 - swap7 - swap8 - swap9 - swap10 - swap11 - swap12 - swap13 - swap14 - swap15 - swap16 - jump // out -tag_4: diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 0609704c5..b6f8d6b53 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -8,7 +8,7 @@ object \"C_10\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_10() @@ -24,7 +24,7 @@ object \"C_10\" { } object \"C_10_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { @@ -71,7 +71,7 @@ object \"C_10\" { memPtr := mload(64) let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } @@ -116,6 +116,10 @@ object \"C_10\" { } + function panic_error() { + invalid() + } + function round_up_to_mul_of_32(value) -> result { result := and(add(value, 31), not(31)) } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 1bc00b338..c18a7298b 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -8,7 +8,7 @@ object \"C_10\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_10() @@ -24,7 +24,7 @@ object \"C_10\" { } object \"C_10_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { @@ -67,7 +67,7 @@ object \"C_10\" { memPtr := mload(64) let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } @@ -88,6 +88,10 @@ object \"C_10\" { } + function panic_error() { + invalid() + } + function shift_right_224_unsigned(value) -> newValue { newValue := diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index fdef77781..360e8956d 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 @@ -8,7 +8,7 @@ object \"C_10\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_10() @@ -24,7 +24,7 @@ object \"C_10\" { } object \"C_10_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { @@ -67,7 +67,7 @@ object \"C_10\" { memPtr := mload(64) let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } @@ -93,6 +93,10 @@ object \"C_10\" { } + function panic_error() { + invalid() + } + function shift_left_224(value) -> newValue { newValue := diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 2a845796d..8de488673 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -8,7 +8,7 @@ object \"C_10\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_10() @@ -24,7 +24,7 @@ object \"C_10\" { } object \"C_10_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { @@ -71,7 +71,7 @@ object \"C_10\" { memPtr := mload(64) let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } @@ -120,6 +120,10 @@ object \"C_10\" { } + function panic_error() { + invalid() + } + function round_up_to_mul_of_32(value) -> result { result := and(add(value, 31), not(31)) } diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 784baf2f4..0851e615d 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -8,7 +8,7 @@ object \"C_10\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if callvalue() { revert(0, 0) } constructor_C_10() @@ -24,7 +24,7 @@ object \"C_10\" { } object \"C_10_deployed\" { code { - mstore(64, 128) + mstore(64, memoryguard(128)) if iszero(lt(calldatasize(), 4)) { @@ -67,7 +67,7 @@ object \"C_10\" { memPtr := mload(64) let newFreePtr := add(memPtr, size) // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) } + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } mstore(64, newFreePtr) } @@ -93,6 +93,10 @@ object \"C_10\" { } + function panic_error() { + invalid() + } + function shift_left_224(value) -> newValue { newValue := diff --git a/test/cmdlineTests/yul_unimplemented/args b/test/cmdlineTests/yul_unimplemented/args new file mode 100644 index 000000000..e869749f2 --- /dev/null +++ b/test/cmdlineTests/yul_unimplemented/args @@ -0,0 +1 @@ +--ir --error-codes diff --git a/test/cmdlineTests/yul_unimplemented/err b/test/cmdlineTests/yul_unimplemented/err new file mode 100644 index 000000000..d6159a1f1 --- /dev/null +++ b/test/cmdlineTests/yul_unimplemented/err @@ -0,0 +1,5 @@ +Error (1834): Unimplemented feature error: setToZero for type t_struct$_S_$4_storage not yet implemented! in FILENAME REMOVED + --> yul_unimplemented/input.sol:9:9: + | +9 | delete str; + | ^^^^^^^^^^ diff --git a/test/cmdlineTests/yul_unimplemented/exit b/test/cmdlineTests/yul_unimplemented/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/yul_unimplemented/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/yul_unimplemented/input.sol b/test/cmdlineTests/yul_unimplemented/input.sol new file mode 100644 index 000000000..d024eeba0 --- /dev/null +++ b/test/cmdlineTests/yul_unimplemented/input.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; +contract test { + struct S { + uint x; + } + S str; + constructor() { + delete str; + } +} \ No newline at end of file diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp index ce99fd585..8f25f9437 100644 --- a/test/contracts/AuctionRegistrar.cpp +++ b/test/contracts/AuctionRegistrar.cpp @@ -417,7 +417,7 @@ BOOST_AUTO_TEST_CASE(auction_simple) BOOST_CHECK_EQUAL(registrar.owner(name), 0); // "wait" until auction end - m_evmHost->tx_context.block_timestamp += m_biddingTime + 10; + m_evmcHost->tx_context.block_timestamp += m_biddingTime + 10; // trigger auction again registrar.reserve(name); BOOST_CHECK_EQUAL(registrar.owner(name), m_sender); @@ -429,7 +429,7 @@ BOOST_AUTO_TEST_CASE(auction_bidding) string name = "x"; unsigned startTime = 0x776347e2; - m_evmHost->tx_context.block_timestamp = startTime; + m_evmcHost->tx_context.block_timestamp = startTime; RegistrarInterface registrar(*this); // initiate auction @@ -437,19 +437,19 @@ BOOST_AUTO_TEST_CASE(auction_bidding) registrar.reserve(name); BOOST_CHECK_EQUAL(registrar.owner(name), 0); // overbid self - m_evmHost->tx_context.block_timestamp = startTime + m_biddingTime - 10; + m_evmcHost->tx_context.block_timestamp = startTime + m_biddingTime - 10; registrar.setNextValue(12); registrar.reserve(name); // another bid by someone else sendEther(account(1), 10 * ether); m_sender = account(1); - m_evmHost->tx_context.block_timestamp = startTime + 2 * m_biddingTime - 50; + m_evmcHost->tx_context.block_timestamp = startTime + 2 * m_biddingTime - 50; registrar.setNextValue(13); registrar.reserve(name); BOOST_CHECK_EQUAL(registrar.owner(name), 0); // end auction by first bidder (which is not highest) trying to overbid again (too late) m_sender = account(0); - m_evmHost->tx_context.block_timestamp = startTime + 4 * m_biddingTime; + m_evmcHost->tx_context.block_timestamp = startTime + 4 * m_biddingTime; registrar.setNextValue(20); registrar.reserve(name); BOOST_CHECK_EQUAL(registrar.owner(name), account(1)); diff --git a/test/externalTests/solc-js/solc-js.sh b/test/externalTests/solc-js/solc-js.sh index 907061f5c..db01a2ae7 100755 --- a/test/externalTests/solc-js/solc-js.sh +++ b/test/externalTests/solc-js/solc-js.sh @@ -48,6 +48,7 @@ function solcjs_test printLog "Copying SMTChecker tests..." cp -Rf "$TEST_DIR"/test/libsolidity/smtCheckerTests test/ + rm -rf test/smtCheckerTests/imports # Update version (needed for some tests) echo "Updating package.json to version $VERSION" diff --git a/test/formal/exp_to_shl.py b/test/formal/exp_to_shl.py new file mode 100644 index 000000000..064d1af3e --- /dev/null +++ b/test/formal/exp_to_shl.py @@ -0,0 +1,34 @@ +from rule import Rule +from opcodes import * +from util import * + +""" +Checking conversion of exp(2, X) to shl(X, 1) +""" + +rule = Rule() +n_bits = 256 + +# Proof of exp(2, X) = shl(X, 1) by induction: +# +# Base case: X = 0, exp(2, 0) = 1 = 1 = shl(0, 1) +# Inductive step: assuming exp(2, X) = shl(X, 1) for X <= N +# to prove: exp(2, N + 1) = shl(N + 1, 1) +# +# Notice that exp(2, N + 1) = 2 * exp(2, N) mod 2**256 +# since exp(2, N) = shl(N, 1), it is enough to show that +# 2 * shl(N, 1) mod 2**256 = shl(N + 1, 1) +# +# Also note that N + 1 < 2**256 + +N = BitVec('N', n_bits) +inductive_step = 2 * SHL(N, 1) + +rule.check( + inductive_step, + If( + N == 2**256 - 1, + 0, + SHL(N + 1, 1) + ) +) diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions.json b/test/libsolidity/ASTJSON/assembly/nested_functions.json index f945494ba..984c05cc9 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions.json @@ -16,7 +16,6 @@ "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "fullyImplemented": true, "id": 8, "linearizedBaseContracts": [ diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json b/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json index 393646221..4f5bfb268 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json @@ -25,7 +25,6 @@ null ], "contractKind": "contract", - "fullyImplemented": true, "linearizedBaseContracts": [ 8 diff --git a/test/libsolidity/ASTJSON/assembly/switch.json b/test/libsolidity/ASTJSON/assembly/switch.json index 9ae71f15c..9a2d1f5c5 100644 --- a/test/libsolidity/ASTJSON/assembly/switch.json +++ b/test/libsolidity/ASTJSON/assembly/switch.json @@ -16,7 +16,6 @@ "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "fullyImplemented": true, "id": 6, "linearizedBaseContracts": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_legacy.json index 92e2e2c61..beddc74e1 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/switch_legacy.json @@ -25,7 +25,6 @@ null ], "contractKind": "contract", - "fullyImplemented": true, "linearizedBaseContracts": [ 6 diff --git a/test/libsolidity/ASTJSON/documentation.sol b/test/libsolidity/ASTJSON/documentation.sol index 089f81e0b..4d354dd26 100644 --- a/test/libsolidity/ASTJSON/documentation.sol +++ b/test/libsolidity/ASTJSON/documentation.sol @@ -1,14 +1,14 @@ -// ---- SOURCE: a +==== Source: a ==== /**This contract is empty*/ contract C {} -// ---- SOURCE: b +==== Source: b ==== /**This contract is empty and has a line-breaking comment.*/ contract C {} -// ---- SOURCE: c +==== Source: c ==== contract C { /** Some comment on state var.*/ uint public state; diff --git a/test/libsolidity/ASTJSON/non_utf8.json b/test/libsolidity/ASTJSON/non_utf8.json index 98db4273f..1a1ea5b96 100644 --- a/test/libsolidity/ASTJSON/non_utf8.json +++ b/test/libsolidity/ASTJSON/non_utf8.json @@ -86,7 +86,7 @@ "typeDescriptions": { "typeIdentifier": "t_stringliteral_8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9", - "typeString": "literal_string (contains invalid UTF-8 sequence at position 0)" + "typeString": "literal_string hex\"ff\"" } }, "nodeType": "VariableDeclarationStatement", diff --git a/test/libsolidity/ASTJSON/non_utf8_legacy.json b/test/libsolidity/ASTJSON/non_utf8_legacy.json index d9430c82d..72b514fda 100644 --- a/test/libsolidity/ASTJSON/non_utf8_legacy.json +++ b/test/libsolidity/ASTJSON/non_utf8_legacy.json @@ -131,7 +131,7 @@ "isPure": true, "lValueRequested": false, "token": "hexString", - "type": "literal_string (contains invalid UTF-8 sequence at position 0)" + "type": "literal_string hex\"ff\"" }, "id": 5, "name": "Literal", diff --git a/test/libsolidity/ASTJSON/unicode.json b/test/libsolidity/ASTJSON/unicode.json index 81c8ad0da..219d89500 100644 --- a/test/libsolidity/ASTJSON/unicode.json +++ b/test/libsolidity/ASTJSON/unicode.json @@ -86,7 +86,7 @@ "typeDescriptions": { "typeIdentifier": "t_stringliteral_cd7a99177cebb3d14b8cc54e313dbf76867c71cd6fbb9a33ce3870dc80e9992b", - "typeString": "literal_string \"Hello \ud83d\ude03\"" + "typeString": "literal_string hex\"48656c6c6f20f09f9883\"" }, "value": "Hello \ud83d\ude03" }, diff --git a/test/libsolidity/ASTJSON/unicode_legacy.json b/test/libsolidity/ASTJSON/unicode_legacy.json index 22976f6f9..f3e4ad321 100644 --- a/test/libsolidity/ASTJSON/unicode_legacy.json +++ b/test/libsolidity/ASTJSON/unicode_legacy.json @@ -131,7 +131,7 @@ "isPure": true, "lValueRequested": false, "token": "unicodeString", - "type": "literal_string \"Hello \ud83d\ude03\"", + "type": "literal_string hex\"48656c6c6f20f09f9883\"", "value": "Hello \ud83d\ude03" }, "id": 5, diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index 76c8e50c7..4e7692562 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -44,6 +44,8 @@ using namespace boost::unit_test; namespace { +string const sourceDelimiter("==== Source: "); + void replaceVersionWithTag(string& _input) { boost::algorithm::replace_all( @@ -81,7 +83,6 @@ ASTJSONTest::ASTJSONTest(string const& _filename) string sourceName; string source; string line; - string const sourceDelimiter("// ---- SOURCE: "); string const delimiter("// ----"); while (getline(file, line)) { @@ -90,7 +91,10 @@ ASTJSONTest::ASTJSONTest(string const& _filename) if (!sourceName.empty()) m_sources.emplace_back(sourceName, source); - sourceName = line.substr(sourceDelimiter.size(), string::npos); + sourceName = line.substr( + sourceDelimiter.size(), + line.size() - " ===="s.size() - sourceDelimiter.size() + ); source = string(); } else if (!line.empty() && !boost::algorithm::starts_with(line, delimiter)) @@ -238,7 +242,7 @@ void ASTJSONTest::printSource(ostream& _stream, string const& _linePrefix, bool for (auto const& source: m_sources) { if (m_sources.size() > 1 || source.first != "a") - _stream << _linePrefix << "// ---- SOURCE: " << source.first << endl << endl; + _stream << _linePrefix << sourceDelimiter << source.first << endl << endl; stringstream stream(source.second); string line; while (getline(stream, line)) diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index 12e088fac..a10604aee 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ evmasm::AssemblyItems compileContract(std::shared_ptr _sourceCode) BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared(_sourceCode))); BOOST_CHECK(!!sourceUnit); + Scoper::assignScopes(*sourceUnit); GlobalContext globalContext; NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion()); diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp deleted file mode 100644 index a7347a21a..000000000 --- a/test/libsolidity/SMTChecker.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - 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 . -*/ -/** - * Unit tests for the SMT checker. - */ - -#include -#include - -#include - -#include - -using namespace std; -using namespace solidity::langutil; - -namespace solidity::frontend::test -{ - -class SMTCheckerFramework: public AnalysisFramework -{ -protected: - std::pair - parseAnalyseAndReturnError( - std::string const& _source, - bool _reportWarnings = false, - bool _insertLicenseAndVersionPragma = true, - bool _allowMultipleErrors = false, - bool _allowRecoveryErrors = false - ) override - { - return AnalysisFramework::parseAnalyseAndReturnError( - "pragma experimental SMTChecker;\n" + _source, - _reportWarnings, - _insertLicenseAndVersionPragma, - _allowMultipleErrors, - _allowRecoveryErrors - ); - } -}; - -BOOST_FIXTURE_TEST_SUITE(SMTChecker, SMTCheckerFramework) - -BOOST_AUTO_TEST_CASE(import_base, *boost::unit_test::label("no_options")) -{ - CompilerStack c; - c.setSources({ - {"base", R"( - pragma solidity >=0.0; - contract Base { - uint x; - address a; - function f() internal returns (uint) { - a = address(this); - ++x; - return 2; - } - } - )"}, - {"der", R"( - pragma solidity >=0.0; - pragma experimental SMTChecker; - import "base"; - contract Der is Base { - function g(uint y) public { - x += f(); - assert(y > x); - } - } - )"} - }); - c.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); - BOOST_CHECK(c.compile()); - - unsigned asserts = 0; - for (auto const& e: c.errors()) - { - string const* msg = e->comment(); - BOOST_REQUIRE(msg); - if (msg->find("Assertion violation") != string::npos) - ++asserts; - } - BOOST_CHECK_EQUAL(asserts, 1); -} - -BOOST_AUTO_TEST_CASE(import_library, *boost::unit_test::label("no_options")) -{ - CompilerStack c; - c.setSources({ - {"lib", R"( - pragma solidity >=0.0; - library L { - uint constant one = 1; - function f() internal pure returns (uint) { - return one; - } - } - )"}, - {"c", R"( - pragma solidity >=0.0; - pragma experimental SMTChecker; - import "lib"; - contract C { - function g(uint x) public pure { - uint y = L.f(); - assert(x > y); - } - } - )"} - }); - c.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); - BOOST_CHECK(c.compile()); - - unsigned asserts = 0; - for (auto const& e: c.errors()) - { - string const* msg = e->comment(); - BOOST_REQUIRE(msg); - if (msg->find("Assertion violation") != string::npos) - ++asserts; - } - BOOST_CHECK_EQUAL(asserts, 1); - -} - - -BOOST_AUTO_TEST_SUITE_END() - -} diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp deleted file mode 100644 index ca6608905..000000000 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - This file is part of solidity. - - solidity is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - solidity is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with solidity. If not, see . -*/ -// SPDX-License-Identifier: GPL-3.0 - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; -using namespace solidity; -using namespace solidity::frontend; -using namespace solidity::frontend::test; -using namespace solidity::util; -using namespace solidity::util::formatting; -using namespace boost::unit_test; - -SMTCheckerJSONTest::SMTCheckerJSONTest(string const& _filename, langutil::EVMVersion _evmVersion) -: SyntaxTest(_filename, _evmVersion) -{ - if (!boost::algorithm::ends_with(_filename, ".sol")) - BOOST_THROW_EXCEPTION(runtime_error("Invalid test contract file name: \"" + _filename + "\".")); - - string jsonFilename = _filename.substr(0, _filename.size() - 4) + ".json"; - if ( - !jsonParseStrict(readFileAsString(jsonFilename), m_smtResponses) || - !m_smtResponses.isObject() - ) - BOOST_THROW_EXCEPTION(runtime_error("Invalid JSON file.")); - - if (ModelChecker::availableSolvers().none()) - m_shouldRun = false; -} - -TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) -{ - StandardCompiler compiler; - - // Run the compiler and retrieve the smtlib2queries (1st run) - 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 - vector outHashes = hashesFromJson(result, "auxiliaryInputRequested", "smtlib2queries"); - - // This is the list of responses provided in the test - string auxInput("auxiliaryInput"); - if (!m_smtResponses.isMember(auxInput)) - BOOST_THROW_EXCEPTION(runtime_error("JSON file does not contain field \"auxiliaryInput\".")); - - vector inHashes = hashesFromJson(m_smtResponses, auxInput, "smtlib2responses"); - - // Ensure that the provided list matches the requested one - if (outHashes != inHashes) - BOOST_THROW_EXCEPTION(runtime_error( - "SMT query hashes differ: " + - boost::algorithm::join(outHashes, ", ") + - " x " + - boost::algorithm::join(inHashes, ", ") - )); - - // Rerun the compiler with the provided hashed (2nd run) - input[auxInput] = m_smtResponses[auxInput]; - Json::Value endResult = compiler.compile(input); - - if (endResult.isMember("errors") && endResult["errors"].isArray()) - { - Json::Value const& errors = endResult["errors"]; - for (auto const& error: errors) - { - if ( - !error.isMember("type") || - !error["type"].isString() - ) - BOOST_THROW_EXCEPTION(runtime_error("Error must have a type.")); - if ( - !error.isMember("message") || - !error["message"].isString() - ) - BOOST_THROW_EXCEPTION(runtime_error("Error must have a message.")); - if (!error.isMember("sourceLocation")) - continue; - Json::Value const& location = error["sourceLocation"]; - if ( - !location.isMember("start") || - !location["start"].isInt() || - !location.isMember("end") || - !location["end"].isInt() - ) - BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end.")); - size_t start = location["start"].asUInt(); - size_t end = location["end"].asUInt(); - std::string sourceName; - if (location.isMember("source") && location["source"].isString()) - sourceName = location["source"].asString(); - if (start >= preamble.size()) - start -= preamble.size(); - if (end >= preamble.size()) - end -= preamble.size(); - m_errorList.emplace_back(SyntaxTestError{ - error["type"].asString(), - error["errorId"].isNull() ? nullopt : optional(langutil::ErrorId{error["errorId"].asUInt()}), - error["message"].asString(), - sourceName, - static_cast(start), - static_cast(end) - }); - } - } - - return conclude(_stream, _linePrefix, _formatted); -} - -vector SMTCheckerJSONTest::hashesFromJson(Json::Value const& _jsonObj, string const& _auxInput, string const& _smtlib) -{ - vector hashes; - Json::Value const& auxInputs = _jsonObj[_auxInput]; - if (!!auxInputs) - { - Json::Value const& smtlib = auxInputs[_smtlib]; - if (!!smtlib) - for (auto const& hashString: smtlib.getMemberNames()) - hashes.push_back(hashString); - } - return hashes; -} - -Json::Value SMTCheckerJSONTest::buildJson(string const& _extra) -{ - string language = "\"language\": \"Solidity\""; - string sources = " \"sources\": { "; - bool first = true; - for (auto [sourceName, sourceContent]: m_sources) - { - string sourceObj = "{ \"content\": \"" + _extra + sourceContent + "\"}"; - if (!first) - sources += ", "; - sources += "\"" + sourceName + "\": " + sourceObj; - first = false; - } - sources += "}"; - string input = "{" + language + ", " + sources + "}"; - Json::Value source; - if (!jsonParseStrict(input, source)) - BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string: " + input)); - return source; -} diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 180e49bd7..c46f59939 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -39,8 +39,8 @@ using namespace boost::unit_test; namespace fs = boost::filesystem; -SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul): - SolidityExecutionFramework(_evmVersion), +SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, vector const& _vmPaths, bool enforceViaYul): + SolidityExecutionFramework(_evmVersion, _vmPaths), EVMVersionRestrictedTestCase(_filename), m_sources(m_reader.sources()), m_lineOffset(m_reader.lineNumber()), @@ -72,6 +72,21 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer else BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + choice + ".")); + string compileToEwasm = m_reader.stringSetting("compileToEwasm", "false"); + if (compileToEwasm == "also") + m_runWithEwasm = true; + else if (compileToEwasm == "false") + m_runWithEwasm = false; + else + BOOST_THROW_EXCEPTION(runtime_error("Invalid compileToEwasm value: " + compileToEwasm + ".")); + + if (m_runWithEwasm && !m_runWithYul) + BOOST_THROW_EXCEPTION(runtime_error("Invalid compileToEwasm value: " + compileToEwasm + ", compileViaYul need to be enabled.")); + + // run ewasm tests only, if an ewasm evmc vm was defined + if (m_runWithEwasm && !m_supportsEwasm) + m_runWithEwasm = false; + m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false); if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2) m_shouldRun = false; @@ -88,156 +103,180 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) { + TestResult result = TestResult::Success; + bool compileViaYul = m_runWithYul || m_enforceViaYul; - for (bool compileViaYul: set{!m_runWithoutYul, m_runWithYul || m_enforceViaYul}) + if (m_runWithoutYul) + result = runTest(_stream, _linePrefix, _formatted, false, false); + + if (compileViaYul && result == TestResult::Success) + result = runTest(_stream, _linePrefix, _formatted, true, false); + + if (m_runWithEwasm && result == TestResult::Success) + result = runTest(_stream, _linePrefix, _formatted, true, true); + + return result; +} + +TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _linePrefix, bool _formatted, bool _compileViaYul, bool _compileToEwasm) +{ + try { - try + bool success = true; + + if (_compileViaYul && _compileToEwasm) + selectVM(evmc_capabilities::EVMC_CAPABILITY_EWASM); + else + selectVM(evmc_capabilities::EVMC_CAPABILITY_EVM1); + + reset(); + + m_compileViaYul = _compileViaYul; + if (_compileToEwasm) { - reset(); - bool success = true; + soltestAssert(m_compileViaYul, ""); + m_compileToEwasm = _compileToEwasm; + } - m_compileViaYul = compileViaYul; - m_compileViaYulCanBeSet = false; + m_compileViaYulCanBeSet = false; - if (compileViaYul) - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl; + if (_compileViaYul) + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl; - for (auto& test: m_tests) - test.reset(); + for (auto& test: m_tests) + test.reset(); - map libraries; + map libraries; - bool constructed = false; + bool constructed = false; - for (auto& test: m_tests) + for (auto& test: m_tests) + { + if (constructed) { - 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(!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; + } + + 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( - deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, - "Failed to deploy library " + test.call().signature + m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()) + .isMember(test.call().signature), + "The function " + test.call().signature + " is not known to the compiler"); + + output = callContractFunctionWithValueNoEncoding( + test.call().signature, test.call().value.value, test.call().arguments.rawBytes() ); - 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; } - if (test.call().isConstructor) - { - if (m_transactionSuccessful == test.call().expectations.failure) - success = false; + if ((m_transactionSuccessful == test.call().expectations.failure) + || (output != test.call().expectations.rawBytes())) + 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" - ); - - output = callContractFunctionWithValueNoEncoding( - test.call().signature, - test.call().value.value, - test.call().arguments.rawBytes() - ); - } - - if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes())) - success = false; - - test.setFailure(!m_transactionSuccessful); - test.setRawBytes(std::move(output)); - test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName())); - } + test.setFailure(!m_transactionSuccessful); + test.setRawBytes(std::move(output)); + test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName())); } + } - if (success && !m_runWithYul && compileViaYul) + if (success && !m_runWithYul && _compileViaYul) + { + 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; + } + + if (!success && (m_runWithYul || !_compileViaYul)) + { + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + for (auto const& test: m_tests) { - 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; + ErrorReporter errorReporter; + _stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl; + _stream << errorReporter.format(_linePrefix, _formatted); } - - if (!success && (m_runWithYul || !compileViaYul)) + _stream << endl; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + for (auto const& test: m_tests) { - 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); - } + 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; - 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 + } + 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) throw; - } - catch (YulException const&) - { - // this should be an error in yul compilation or translation + } + catch (std::exception const&) + { + if (!_compileViaYul || m_runWithYul) throw; - } - catch (boost::exception const&) - { - if (compileViaYul && !m_runWithYul) - continue; + } + catch (...) + { + if (!_compileViaYul || m_runWithYul) throw; - } - catch (std::exception const&) - { - if (compileViaYul && !m_runWithYul) - continue; - throw; - } - catch (...) - { - if (compileViaYul && !m_runWithYul) - continue; - throw; - } } return TestResult::Success; diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index 646e7e00b..acb656763 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -40,9 +40,9 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict { public: static std::unique_ptr create(Config const& _options) - { return std::make_unique(_options.filename, _options.evmVersion, _options.enforceCompileViaYul); } + { return std::make_unique(_options.filename, _options.evmVersion, _options.vmPaths, _options.enforceCompileViaYul); } - explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, bool _enforceViaYul = false); + explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, std::vector const& _vmPaths, 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; @@ -59,10 +59,12 @@ public: /// Returns true if deployment was successful, false otherwise. bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map const& _libraries = {}); private: + TestResult runTest(std::ostream& _stream, std::string const& _linePrefix, bool _formatted, bool _compileViaYul, bool _compileToEwasm); SourceMap m_sources; std::size_t m_lineOffset; std::vector m_tests; bool m_runWithYul = false; + bool m_runWithEwasm = false; bool m_runWithoutYul = true; bool m_enforceViaYul = false; bool m_runWithABIEncoderV1Only = false; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d3398f510..5dc022137 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -48,18 +48,38 @@ using namespace solidity::util; using namespace solidity::test; using namespace solidity::langutil; -#define ALSO_VIA_YUL(CODE) \ -{ \ - { CODE } \ - reset(); \ - m_compileViaYul = true; \ - { CODE } \ +#define ALSO_VIA_YUL(CODE) \ +{ \ + m_doEwasmTestrun = true; \ + \ + m_compileViaYul = false; \ + m_compileToEwasm = false; \ + { CODE } \ + \ + m_compileViaYul = true; \ + reset(); \ + { CODE } \ + \ + if (m_doEwasmTestrun) \ + { \ + m_compileToEwasm = true; \ + reset(); \ + { CODE } \ + } \ } +#define DISABLE_EWASM_TESTRUN() \ + { m_doEwasmTestrun = false; } + namespace solidity::frontend::test { -BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityExecutionFramework) +struct SolidityEndToEndTestExecutionFramework: public SolidityExecutionFramework +{ + bool m_doEwasmTestrun = false; +}; + +BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityEndToEndTestExecutionFramework) int constexpr roundTo32(int _num) { @@ -115,6 +135,8 @@ BOOST_AUTO_TEST_CASE(recursive_calls) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); function recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256 { @@ -140,6 +162,8 @@ BOOST_AUTO_TEST_CASE(while_loop) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto while_loop_cpp = [](u256 const& n) -> u256 @@ -168,6 +192,8 @@ BOOST_AUTO_TEST_CASE(do_while_loop) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto do_while_loop_cpp = [](u256 const& n) -> u256 @@ -213,6 +239,8 @@ BOOST_AUTO_TEST_CASE(do_while_loop_multiple_local_vars) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto do_while = [](u256 n) -> u256 @@ -263,6 +291,8 @@ BOOST_AUTO_TEST_CASE(nested_loops) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto nested_loops_cpp = [](u256 n) -> u256 @@ -329,6 +359,8 @@ BOOST_AUTO_TEST_CASE(nested_loops_multiple_local_vars) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto nested_loops_cpp = [](u256 n) -> u256 @@ -383,6 +415,8 @@ BOOST_AUTO_TEST_CASE(for_loop_multiple_local_vars) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto for_loop = [](u256 n) -> u256 @@ -444,6 +478,8 @@ BOOST_AUTO_TEST_CASE(nested_for_loop_multiple_local_vars) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto for_loop = [](u256 n) -> u256 @@ -484,6 +520,8 @@ BOOST_AUTO_TEST_CASE(for_loop) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto for_loop_cpp = [](u256 const& n) -> u256 @@ -512,6 +550,8 @@ BOOST_AUTO_TEST_CASE(for_loop_empty) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto for_loop_empty_cpp = []() -> u256 @@ -542,6 +582,8 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto for_loop_simple_init_expr_cpp = [](u256 const& n) -> u256 @@ -665,6 +707,8 @@ BOOST_AUTO_TEST_CASE(many_local_variables) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256 { @@ -689,6 +733,8 @@ BOOST_AUTO_TEST_CASE(short_circuiting) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto short_circuiting_cpp = [](u256 n) -> u256 @@ -801,6 +847,8 @@ BOOST_AUTO_TEST_CASE(compound_assign) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 value1; @@ -863,6 +911,8 @@ BOOST_AUTO_TEST_CASE(mapping_state) map m_voted; }; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); Ballot ballot; @@ -936,6 +986,8 @@ BOOST_AUTO_TEST_CASE(mapping_state_inc_dec) return --table[value++]; }; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); value = 0; table.clear(); @@ -962,6 +1014,8 @@ BOOST_AUTO_TEST_CASE(multi_level_mapping) else return table[_x][_y] = _z; }; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); table.clear(); @@ -998,6 +1052,8 @@ BOOST_AUTO_TEST_CASE(constructor) }; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); testContractAgainstCpp("get(uint256)", get, u256(6)); testContractAgainstCpp("get(uint256)", get, u256(7)); @@ -1016,12 +1072,12 @@ BOOST_AUTO_TEST_CASE(blockchain) } } )"; - m_evmHost->tx_context.block_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212")); - m_evmHost->newBlock(); - m_evmHost->newBlock(); - m_evmHost->newBlock(); - m_evmHost->newBlock(); - m_evmHost->newBlock(); + m_evmcHost->tx_context.block_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212")); + m_evmcHost->newBlock(); + m_evmcHost->newBlock(); + m_evmcHost->newBlock(); + m_evmcHost->newBlock(); + m_evmcHost->newBlock(); compileAndRun(sourceCode, 27); ABI_CHECK(callContractFunctionWithValue("someInfo()", 28), encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7)); } @@ -1038,6 +1094,8 @@ BOOST_AUTO_TEST_CASE(send_ether) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + u256 amount(250); compileAndRun(sourceCode, amount + 1); u160 address(23); @@ -1070,6 +1128,8 @@ BOOST_AUTO_TEST_CASE(transfer_ether) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode, 0, "B"); u160 const nonPayableRecipient = m_contractAddress; compileAndRun(sourceCode, 0, "C"); @@ -1110,6 +1170,8 @@ BOOST_AUTO_TEST_CASE(log0) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("a()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1129,6 +1191,8 @@ BOOST_AUTO_TEST_CASE(log1) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("a()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1149,6 +1213,8 @@ BOOST_AUTO_TEST_CASE(log2) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("a()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1170,6 +1236,8 @@ BOOST_AUTO_TEST_CASE(log3) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("a()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1191,6 +1259,8 @@ BOOST_AUTO_TEST_CASE(log4) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("a()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1212,6 +1282,8 @@ BOOST_AUTO_TEST_CASE(log_in_constructor) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); BOOST_REQUIRE_EQUAL(numLogs(), 1); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); @@ -1235,6 +1307,8 @@ BOOST_AUTO_TEST_CASE(selfdestruct) u256 amount(130); u160 address(23); ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode, amount); ABI_CHECK(callContractFunction("a(address)", address), bytes()); BOOST_CHECK(!addressHasCode(m_contractAddress)); @@ -1665,6 +1739,8 @@ BOOST_AUTO_TEST_CASE(gaslimit) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); auto result = callContractFunction("f()"); ABI_CHECK(result, encodeArgs(gasLimit())); @@ -1681,6 +1757,8 @@ BOOST_AUTO_TEST_CASE(gasprice) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); ABI_CHECK(callContractFunction("f()"), encodeArgs(gasPrice())); ) @@ -1772,6 +1850,8 @@ BOOST_AUTO_TEST_CASE(event) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 value(18); u256 id(0x1234); @@ -1800,6 +1880,8 @@ BOOST_AUTO_TEST_CASE(event_emit) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 value(18); u256 id(0x1234); @@ -1826,6 +1908,8 @@ BOOST_AUTO_TEST_CASE(event_no_arguments) )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("deposit()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1850,6 +1934,8 @@ BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("f()"); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1889,6 +1975,8 @@ BOOST_AUTO_TEST_CASE(events_with_same_name) u160 const c_loggedAddress = m_contractAddress; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1950,6 +2038,8 @@ BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit) u160 const c_loggedAddress = m_contractAddress; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); BOOST_REQUIRE_EQUAL(numLogs(), 1); @@ -1985,6 +2075,8 @@ BOOST_AUTO_TEST_CASE(event_anonymous) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); callContractFunction("deposit()"); BOOST_REQUIRE_EQUAL(numLogTopics(0), 0); @@ -2002,6 +2094,8 @@ BOOST_AUTO_TEST_CASE(event_anonymous_with_topics) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 value(18); u256 id(0x1234); @@ -2028,6 +2122,8 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 value(18); u256 id(0x1234); @@ -2247,6 +2343,8 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_storage) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 x(42); callContractFunction("createEvent(uint256)", x); @@ -2276,6 +2374,8 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); u256 x(42); callContractFunction("createEvent(uint256)", x); @@ -2365,6 +2465,8 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8)); ABI_CHECK(callContractFunction("f(uint256,uint256)", 5, 9), encodeArgs(9, 8)); @@ -2987,6 +3089,8 @@ BOOST_AUTO_TEST_CASE(fixed_array_cleanup) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); BOOST_CHECK(storageEmpty(m_contractAddress)); ABI_CHECK(callContractFunction("fill()"), bytes()); @@ -3010,6 +3114,8 @@ BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); BOOST_CHECK(storageEmpty(m_contractAddress)); ABI_CHECK(callContractFunction("fill()"), bytes()); @@ -3037,6 +3143,8 @@ BOOST_AUTO_TEST_CASE(dynamic_array_cleanup) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); BOOST_CHECK(storageEmpty(m_contractAddress)); ABI_CHECK(callContractFunction("fill()"), bytes()); @@ -4305,6 +4413,8 @@ BOOST_AUTO_TEST_CASE(string_as_mapping_key) }; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode, 0, "Test"); for (unsigned i = 0; i < strings.size(); i++) ABI_CHECK(callContractFunction( @@ -5415,6 +5525,8 @@ BOOST_AUTO_TEST_CASE(no_nonpayable_circumvention_by_modifier) } )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs()); BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); @@ -5527,6 +5639,8 @@ BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) contract C2 {} )"; ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode, 0, "C1"); compileAndRun(sourceCode, 0, "C2"); ) diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index 6ad8ddd15..4a0745431 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -43,6 +43,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( entry.second = addPreamble(entry.second); m_compiler.reset(); + m_compiler.enableEwasmGeneration(m_compileToEwasm); m_compiler.setSources(sourcesWithPreamble); m_compiler.setLibraries(_libraryAddresses); m_compiler.setRevertStringBehaviour(m_revertStrings); @@ -53,6 +54,12 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( m_compiler.setRevertStringBehaviour(m_revertStrings); if (!m_compiler.compile()) { + // The testing framework expects an exception for + // "unimplemented" yul IR generation. + if (m_compileViaYul) + for (auto const& error: m_compiler.errors()) + if (error->type() == langutil::Error::Type::CodeGenerationError) + BOOST_THROW_EXCEPTION(*error); langutil::SourceReferenceFormatter formatter(std::cerr); for (auto const& error: m_compiler.errors()) @@ -63,38 +70,40 @@ bytes SolidityExecutionFramework::multiSourceCompileContract( evmasm::LinkerObject obj; if (m_compileViaYul) { - // Try compiling twice: If the first run fails due to stack errors, forcefully enable - // the optimizer. - for (bool forceEnableOptimizer: {false, true}) + if (m_compileToEwasm) + obj = m_compiler.ewasmObject(contractName); + else { - OptimiserSettings optimiserSettings = m_optimiserSettings; - if (!forceEnableOptimizer && !optimiserSettings.runYulOptimiser) + // Try compiling twice: If the first run fails due to stack errors, forcefully enable + // the optimizer. + for (bool forceEnableOptimizer: {false, true}) { - // Enable some optimizations on the first run - optimiserSettings.runYulOptimiser = true; - optimiserSettings.yulOptimiserSteps = "uljmul jmul"; - } - else if (forceEnableOptimizer) - optimiserSettings = OptimiserSettings::full(); + OptimiserSettings optimiserSettings = m_optimiserSettings; + if (!forceEnableOptimizer && !optimiserSettings.runYulOptimiser) + { + // Enable some optimizations on the first run + optimiserSettings.runYulOptimiser = true; + optimiserSettings.yulOptimiserSteps = "uljmul jmul"; + } + else if (forceEnableOptimizer) + optimiserSettings = OptimiserSettings::full(); - yul::AssemblyStack asmStack( - m_evmVersion, - yul::AssemblyStack::Language::StrictAssembly, - optimiserSettings - ); - bool analysisSuccessful = asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName)); - solAssert(analysisSuccessful, "Code that passed analysis in CompilerStack can't have errors"); + yul::AssemblyStack + asmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, optimiserSettings); + bool analysisSuccessful = asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName)); + solAssert(analysisSuccessful, "Code that passed analysis in CompilerStack can't have errors"); - try - { - asmStack.optimize(); - obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode); - break; - } - catch (...) - { - if (forceEnableOptimizer || optimiserSettings == OptimiserSettings::full()) - throw; + try + { + asmStack.optimize(); + obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode); + break; + } + catch (...) + { + if (forceEnableOptimizer || optimiserSettings == OptimiserSettings::full()) + throw; + } } } } diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index 9efe22b20..5b375cd14 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -43,8 +43,8 @@ class SolidityExecutionFramework: public solidity::test::ExecutionFramework public: SolidityExecutionFramework(): m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} - explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion): - ExecutionFramework(_evmVersion), m_showMetadata(solidity::test::CommonOptions::get().showMetadata) + explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion, std::vector const& _vmPaths): + ExecutionFramework(_evmVersion, _vmPaths), m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} bytes const& compileAndRunWithoutCheck( @@ -76,8 +76,10 @@ public: /// the latter only if it is required. static std::string addPreamble(std::string const& _sourceCode); protected: + solidity::frontend::CompilerStack m_compiler; bool m_compileViaYul = false; + bool m_compileToEwasm = false; bool m_showMetadata = false; RevertStrings m_revertStrings = RevertStrings::Default; }; diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 91a41a65b..8c0ce780d 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,7 @@ bytes compileFirstExpression( ErrorList errors; ErrorReporter errorReporter(errors); GlobalContext globalContext; + Scoper::assignScopes(*sourceUnit); NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); resolver.registerDeclarations(*sourceUnit); BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed"); diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 65a8026a4..1ecd0e9f9 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(function_no_implementation) std::vector> nodes = sourceUnit->nodes(); ContractDefinition* contract = dynamic_cast(nodes[1].get()); BOOST_REQUIRE(contract); - BOOST_CHECK(!contract->annotation().unimplementedDeclarations.empty()); + BOOST_CHECK(!contract->annotation().unimplementedDeclarations->empty()); BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented()); } @@ -68,10 +68,10 @@ BOOST_AUTO_TEST_CASE(abstract_contract) ContractDefinition* base = dynamic_cast(nodes[1].get()); ContractDefinition* derived = dynamic_cast(nodes[2].get()); BOOST_REQUIRE(base); - BOOST_CHECK(!base->annotation().unimplementedDeclarations.empty()); + BOOST_CHECK(!base->annotation().unimplementedDeclarations->empty()); BOOST_CHECK(!base->definedFunctions()[0]->isImplemented()); BOOST_REQUIRE(derived); - BOOST_CHECK(derived->annotation().unimplementedDeclarations.empty()); + BOOST_CHECK(derived->annotation().unimplementedDeclarations->empty()); BOOST_CHECK(derived->definedFunctions()[0]->isImplemented()); } @@ -87,9 +87,9 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload) ContractDefinition* base = dynamic_cast(nodes[1].get()); ContractDefinition* derived = dynamic_cast(nodes[2].get()); BOOST_REQUIRE(base); - BOOST_CHECK(!base->annotation().unimplementedDeclarations.empty()); + BOOST_CHECK(!base->annotation().unimplementedDeclarations->empty()); BOOST_REQUIRE(derived); - BOOST_CHECK(!derived->annotation().unimplementedDeclarations.empty()); + BOOST_CHECK(!derived->annotation().unimplementedDeclarations->empty()); } BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor) @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor) BOOST_CHECK_EQUAL(nodes.size(), 3); ContractDefinition* derived = dynamic_cast(nodes[2].get()); BOOST_REQUIRE(derived); - BOOST_CHECK(!derived->annotation().unimplementedDeclarations.empty()); + BOOST_CHECK(!derived->annotation().unimplementedDeclarations->empty()); } BOOST_AUTO_TEST_CASE(function_canonical_signature) diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 53c93c726..41fe4b53b 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -599,42 +599,6 @@ BOOST_AUTO_TEST_CASE(complex_import) BOOST_CHECK(successParse(text)); } -BOOST_AUTO_TEST_CASE(recursion_depth1) -{ - string text("contract C { bytes"); - for (size_t i = 0; i < 30000; i++) - text += "["; - CHECK_PARSE_ERROR(text.c_str(), "Maximum recursion depth reached during parsing"); -} - -BOOST_AUTO_TEST_CASE(recursion_depth2) -{ - string text("contract C { function f() {"); - for (size_t i = 0; i < 30000; i++) - text += "{"; - CHECK_PARSE_ERROR(text, "Maximum recursion depth reached during parsing"); -} - -BOOST_AUTO_TEST_CASE(recursion_depth3) -{ - string text("contract C { function f() { uint x = f("); - for (size_t i = 0; i < 30000; i++) - text += "("; - CHECK_PARSE_ERROR(text, "Maximum recursion depth reached during parsing"); -} - -BOOST_AUTO_TEST_CASE(recursion_depth4) -{ - string text("contract C { function f() { uint a;"); - for (size_t i = 0; i < 30000; i++) - text += "("; - text += "a"; - for (size_t i = 0; i < 30000; i++) - text += "++)"; - text += "}}"; - CHECK_PARSE_ERROR(text, "Maximum recursion depth reached during parsing"); -} - BOOST_AUTO_TEST_CASE(inline_asm_end_location) { auto sourceCode = std::string(R"( diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index d71cf10f1..b02ebbe2e 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -29,6 +29,7 @@ #include #include +#include #include using namespace std; @@ -1235,9 +1236,16 @@ BOOST_AUTO_TEST_CASE(use_stack_optimization) BOOST_REQUIRE(contract["evm"]["bytecode"]["object"].isString()); BOOST_CHECK(contract["evm"]["bytecode"]["object"].asString().length() > 20); - // Now disable stack optimizations + // Now disable stack optimizations and UnusedFunctionParameterPruner (p) // results in "stack too deep" + string optimiserSteps = OptimiserSettings::DefaultYulOptimiserSteps; + optimiserSteps.erase( + remove_if(optimiserSteps.begin(), optimiserSteps.end(), [](char ch) { return ch == 'p'; }), + optimiserSteps.end() + ); parsedInput["settings"]["optimizer"]["details"]["yulDetails"]["stackAllocation"] = false; + parsedInput["settings"]["optimizer"]["details"]["yulDetails"]["optimizerSteps"] = optimiserSteps; + result = compiler.compile(parsedInput); BOOST_REQUIRE(result["errors"].isArray()); BOOST_CHECK(result["errors"][0]["severity"] == "error"); diff --git a/test/libsolidity/gasTests/abiv2.sol b/test/libsolidity/gasTests/abiv2.sol index 1fd96ff76..9042c8a51 100644 --- a/test/libsolidity/gasTests/abiv2.sol +++ b/test/libsolidity/gasTests/abiv2.sol @@ -14,9 +14,9 @@ contract C { } // ---- // creation: -// codeDepositCost: 1094400 -// executionCost: 1134 -// totalCost: 1095534 +// codeDepositCost: 1106800 +// executionCost: 1147 +// totalCost: 1107947 // external: // a(): 1130 // b(uint256): infinite diff --git a/test/libsolidity/gasTests/abiv2_optimised.sol b/test/libsolidity/gasTests/abiv2_optimised.sol index 74cd89a42..1069a6bdf 100644 --- a/test/libsolidity/gasTests/abiv2_optimised.sol +++ b/test/libsolidity/gasTests/abiv2_optimised.sol @@ -17,9 +17,9 @@ contract C { // optimize-yul: true // ---- // creation: -// codeDepositCost: 616600 -// executionCost: 651 -// totalCost: 617251 +// codeDepositCost: 604400 +// executionCost: 638 +// totalCost: 605038 // external: // a(): 1029 // b(uint256): 2084 diff --git a/test/libsolidity/semanticTests/arithmetics/signed_mod.sol b/test/libsolidity/semanticTests/arithmetics/signed_mod.sol new file mode 100644 index 000000000..a992bd0be --- /dev/null +++ b/test/libsolidity/semanticTests/arithmetics/signed_mod.sol @@ -0,0 +1,14 @@ +contract C { + function f(int a, int b) public pure returns (int) { + return a % b; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(int256,int256): 7, 5 -> 2 +// f(int256,int256): 7, -5 -> 2 +// f(int256,int256): -7, 5 -> -2 +// f(int256,int256): -7, 5 -> -2 +// f(int256,int256): -5, -5 -> 0 diff --git a/test/libsolidity/semanticTests/array/array_push_packed_array.sol b/test/libsolidity/semanticTests/array/array_push_packed_array.sol index dd5e2e855..e99221671 100644 --- a/test/libsolidity/semanticTests/array/array_push_packed_array.sol +++ b/test/libsolidity/semanticTests/array/array_push_packed_array.sol @@ -12,5 +12,7 @@ contract c { } } +// ==== +// compileViaYul: also // ---- // test() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/array/copying/array_storage_multi_items_per_slot.sol b/test/libsolidity/semanticTests/array/copying/array_storage_multi_items_per_slot.sol new file mode 100644 index 000000000..226a5ea89 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/array_storage_multi_items_per_slot.sol @@ -0,0 +1,16 @@ +contract C { + uint8[33] a; + uint32[9] b; + uint120[3] c; + + function f() public returns (uint8, uint32, uint120) { + a[32] = 1; a[31] = 2; a[30] = 3; + b[0] = 1; b[1] = 2; b[2] = 3; + c[2] = 3; c[1] = 1; + return (a[32], b[1], c[2]); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2, 3 diff --git a/test/libsolidity/semanticTests/freeFunctions/free_namesake_contract_function.sol b/test/libsolidity/semanticTests/freeFunctions/free_namesake_contract_function.sol new file mode 100644 index 000000000..3d21d92f4 --- /dev/null +++ b/test/libsolidity/semanticTests/freeFunctions/free_namesake_contract_function.sol @@ -0,0 +1,10 @@ +function f() pure returns (uint) { return 1337; } +contract C { + function f() public pure returns (uint) { + return f(); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> FAILURE diff --git a/test/libsolidity/semanticTests/multiSource/circular_import.sol b/test/libsolidity/semanticTests/multiSource/circular_import.sol new file mode 100644 index 000000000..671ac85dc --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/circular_import.sol @@ -0,0 +1,15 @@ +==== Source: s1.sol ==== +import {f as g} from "s2.sol"; +function f() pure returns (uint) { return 1; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +function f() pure returns (uint) { return 2; } +contract C { + function foo() public pure returns (uint) { + return f() - g(); + } +} +// ==== +// compileViaYul: also +// ---- +// foo() -> 1 diff --git a/test/libsolidity/semanticTests/multiSource/circular_import_2.sol b/test/libsolidity/semanticTests/multiSource/circular_import_2.sol new file mode 100644 index 000000000..2c458aa93 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/circular_import_2.sol @@ -0,0 +1,14 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } +contract C { + function foo() public pure returns (uint) { + return h() - f() - g(); + } +} +// ---- +// foo() -> -4 diff --git a/test/libsolidity/semanticTests/multiSource/circular_reimport.sol b/test/libsolidity/semanticTests/multiSource/circular_reimport.sol new file mode 100644 index 000000000..05c0eeb57 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/circular_reimport.sol @@ -0,0 +1,16 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } +==== Source: s3.sol ==== +import "s1.sol"; +contract C { + function foo() public pure returns (uint) { + return f() - g() - h(); + } +} +// ---- +// foo() -> -4 diff --git a/test/libsolidity/semanticTests/multiSource/circular_reimport_2.sol b/test/libsolidity/semanticTests/multiSource/circular_reimport_2.sol new file mode 100644 index 000000000..14f5123f3 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/circular_reimport_2.sol @@ -0,0 +1,16 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } +==== Source: s3.sol ==== +import "s2.sol"; +contract C { + function foo() public pure returns (uint) { + return f() - g() - h(); + } +} +// ---- +// foo() -> -4 diff --git a/test/libsolidity/semanticTests/multiSource/free_different_interger_types.sol b/test/libsolidity/semanticTests/multiSource/free_different_interger_types.sol new file mode 100644 index 000000000..8f57caff8 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/free_different_interger_types.sol @@ -0,0 +1,14 @@ +==== Source: s1.sol ==== +function f(uint24) pure returns (uint) { return 24; } +function g(bool) pure returns (bool) { return true; } +==== Source: s2.sol ==== +import {f as g, g as g} from "s1.sol"; +contract C { + function foo() public pure returns (uint, bool) { + return (g(2), g(false)); + } +} +// ==== +// compileViaYul: also +// ---- +// foo() -> 24, true diff --git a/test/libsolidity/semanticTests/multiSource/free_function_resolution_base_contract.sol b/test/libsolidity/semanticTests/multiSource/free_function_resolution_base_contract.sol new file mode 100644 index 000000000..ad4a11db8 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/free_function_resolution_base_contract.sol @@ -0,0 +1,18 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function g() public pure returns (uint) { + return f(); + } +} +==== Source: s2.sol ==== +import "s1.sol"; +contract D is C { + function h() public pure returns (uint) { + return g(); + } +} +// ==== +// compileViaYul: also +// ---- +// h() -> 1337 diff --git a/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual.sol b/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual.sol new file mode 100644 index 000000000..f69f79ee6 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual.sol @@ -0,0 +1,18 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function g() public pure virtual returns (uint) { + return f() + 1; + } +} +==== Source: s2.sol ==== +import "s1.sol"; +contract D is C { + function g() public pure override returns (uint) { + return f(); + } +} +// ==== +// compileViaYul: also +// ---- +// g() -> 1337 diff --git a/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual_super.sol b/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual_super.sol new file mode 100644 index 000000000..b8d1be4d5 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual_super.sol @@ -0,0 +1,18 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function g() public pure virtual returns (uint) { + return f(); + } +} +==== Source: s2.sol ==== +import "s1.sol"; +contract D is C { + function g() public pure override returns (uint) { + return super.g(); + } +} +// ==== +// compileViaYul: also +// ---- +// g() -> 1337 diff --git a/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual_transitive.sol b/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual_transitive.sol new file mode 100644 index 000000000..d9611ce33 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/free_function_resolution_override_virtual_transitive.sol @@ -0,0 +1,25 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function g() public pure virtual returns (uint) { + return f(); + } +} +==== Source: s2.sol ==== +import "s1.sol"; +contract D is C { + function g() public pure virtual override returns (uint) { + return super.g() + 1; + } +} +==== Source: s3.sol ==== +import "s2.sol"; +contract E is D { + function g() public pure override returns (uint) { + return super.g() + 1; + } +} +// ==== +// compileViaYul: also +// ---- +// g() -> 1339 diff --git a/test/libsolidity/semanticTests/multiSource/free_function_transitive_import.sol b/test/libsolidity/semanticTests/multiSource/free_function_transitive_import.sol new file mode 100644 index 000000000..356df96e1 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/free_function_transitive_import.sol @@ -0,0 +1,27 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function g() public pure returns (uint) { + return f(); + } +} +==== Source: s2.sol ==== +import "s1.sol"; +contract D is C { + function h() public pure returns (uint) { + return g(); + } +} +==== Source: s3.sol ==== +import "s2.sol"; +import {f as f} from "s2.sol"; +contract E is D { + function i() public pure returns (uint) { + return f(); + } +} + +// ==== +// compileViaYul: also +// ---- +// i() -> 1337 diff --git a/test/libsolidity/semanticTests/multiSource/imported_free_function_via_alias.sol b/test/libsolidity/semanticTests/multiSource/imported_free_function_via_alias.sol new file mode 100644 index 000000000..b4a1b7800 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/imported_free_function_via_alias.sol @@ -0,0 +1,19 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function g() public pure virtual returns (uint) { + return f(); + } +} +==== Source: s2.sol ==== +import "s1.sol" as M; +function f() pure returns (uint) { return 6; } +contract D is M.C { + function g() public pure override returns (uint) { + return super.g() + f() * 10000; + } +} +// ==== +// compileViaYul: also +// ---- +// g() -> 61337 diff --git a/test/libsolidity/semanticTests/multiSource/imported_free_function_via_alias_direct_call.sol b/test/libsolidity/semanticTests/multiSource/imported_free_function_via_alias_direct_call.sol new file mode 100644 index 000000000..a770a5f9d --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/imported_free_function_via_alias_direct_call.sol @@ -0,0 +1,14 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +function f() pure returns (uint) { return 6; } +contract D { + function h() public pure returns (uint) { + return g() + f() * 10000; + } +} +// ==== +// compileViaYul: also +// ---- +// h() -> 61337 diff --git a/test/libsolidity/semanticTests/multiSource/reimport_imported_function.sol b/test/libsolidity/semanticTests/multiSource/reimport_imported_function.sol new file mode 100644 index 000000000..78e65a540 --- /dev/null +++ b/test/libsolidity/semanticTests/multiSource/reimport_imported_function.sol @@ -0,0 +1,15 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +==== Source: s3.sol ==== +import {g as h} from "s2.sol"; +contract C { + function foo() public pure returns (uint) { + return h(); + } +} +// ==== +// compileViaYul: also +// ---- +// foo() -> 1337 diff --git a/test/libsolidity/semanticTests/various/codebalance_assembly.sol b/test/libsolidity/semanticTests/various/codebalance_assembly.sol new file mode 100644 index 000000000..2df9c5b4f --- /dev/null +++ b/test/libsolidity/semanticTests/various/codebalance_assembly.sol @@ -0,0 +1,28 @@ +contract C { + constructor() payable {} + + function f() public returns (uint256 ret) { + assembly { + ret := balance(0) + } + } + function g() public returns (uint256 ret) { + assembly { + ret := balance(1) + } + } + function h() public returns (uint256 ret) { + assembly { + ret := balance(address()) + } + } +} + +// ==== +// EVMVersion: >=constantinople +// compileViaYul: also +// ---- +// constructor(), 23 wei -> +// f() -> 0 +// g() -> 1 +// h() -> 23 diff --git a/test/libsolidity/semanticTests/various/codehash_assembly.sol b/test/libsolidity/semanticTests/various/codehash_assembly.sol new file mode 100644 index 000000000..4ac2a93f1 --- /dev/null +++ b/test/libsolidity/semanticTests/various/codehash_assembly.sol @@ -0,0 +1,25 @@ +contract C { + function f() public returns (bytes32 ret) { + assembly { + ret := extcodehash(0) + } + } + function g() public returns (bytes32 ret) { + assembly { + ret := extcodehash(1) + } + } + function h() public returns (bool ret) { + assembly { + ret := iszero(iszero(extcodehash(address()))) + } + } +} + +// ==== +// EVMVersion: >=constantinople +// compileViaYul: also +// ---- +// f() -> 0 +// g() -> 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 +// h() -> true diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol new file mode 100644 index 000000000..86509cfe4 --- /dev/null +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol @@ -0,0 +1,23 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + bool[] b; + } + + function f() public returns (uint256, bool[][2] memory, S[2] memory, uint256) { + return ( + 5, + [new bool[](1), new bool[](2)], + [S(new bool[](2)), S(new bool[](5))], + 6 + ); + } + + function g() public returns (uint256, uint256) { + (uint256 a, , , uint256 b) = this.f(); + return (a, b); + } +} +// ---- +// g() -> 5, 6 diff --git a/test/libsolidity/semanticTests/viaYul/exp_neg.sol b/test/libsolidity/semanticTests/viaYul/exp_neg.sol index aa2f5eb18..149e9159a 100644 --- a/test/libsolidity/semanticTests/viaYul/exp_neg.sol +++ b/test/libsolidity/semanticTests/viaYul/exp_neg.sol @@ -25,4 +25,9 @@ contract C { // f(int256,uint256): -2, 2 -> 4 // f(int256,uint256): -7, 63 -> -174251498233690814305510551794710260107945042018748343 // f(int256,uint256): -128, 2 -> 0x4000 -// f(int256,uint256): -1, 115792089237316195423570985008687907853269984665640564039457584007913129639935 -> -1 \ No newline at end of file +// f(int256,uint256): -1, 115792089237316195423570985008687907853269984665640564039457584007913129639935 -> -1 +// f(int256,uint256): -2, 255 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968 +// f(int256,uint256): -8, 85 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968 +// f(int256,uint256): -131072, 15 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968 +// f(int256,uint256): -32, 51 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968 +// f(int256,uint256): -57896044618658097711785492504343953926634992332820282019728792003956564819968, 1 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968 diff --git a/test/libsolidity/semanticTests/viaYul/stackLimitEvasion/inlined.sol b/test/libsolidity/semanticTests/viaYul/stackLimitEvasion/inlined.sol new file mode 100644 index 000000000..b9c050b46 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/stackLimitEvasion/inlined.sol @@ -0,0 +1,53 @@ +contract C { + uint256[1024] s; + function f() public returns (uint256 x) { + x = 42; + uint256 x0 = s[0]; + uint256 x1 = s[1]; + uint256 x2 = s[2]; + uint256 x3 = s[3]; + uint256 x4 = s[4]; + uint256 x5 = s[5]; + uint256 x6 = s[6]; + uint256 x7 = s[7]; + uint256 x8 = s[8]; + uint256 x9 = s[9]; + uint256 x10 = s[10]; + uint256 x11 = s[11]; + uint256 x12 = s[12]; + uint256 x13 = s[13]; + uint256 x14 = s[14]; + uint256 x15 = s[15]; + uint256 x16 = s[16]; + uint256 x17 = s[17]; + uint256 x18 = s[18]; + s[1000] = x0 + 2; + s[118] = x18; + s[117] = x17; + s[116] = x16; + s[115] = x15; + s[114] = x14; + s[113] = x13; + s[112] = x12; + s[111] = x11; + s[110] = x10; + s[109] = x9; + s[108] = x8; + s[107] = x7; + s[106] = x6; + s[105] = x5; + s[104] = x4; + s[103] = x3; + s[102] = x2; + s[101] = x1; + s[100] = x0; + } + function test() public view returns(uint256) { + return s[1000]; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 0x2a +// test() -> 2 diff --git a/test/libsolidity/semanticTests/viaYul/stackLimitEvasion/non_inlined.sol b/test/libsolidity/semanticTests/viaYul/stackLimitEvasion/non_inlined.sol new file mode 100644 index 000000000..9fa3f7117 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/stackLimitEvasion/non_inlined.sol @@ -0,0 +1,57 @@ +contract C { + uint256[1024] s; + function g() public returns (uint256) { + // try to prevent inlining + return f() + f() + f() + f() + f(); + } + function f() public returns (uint256 x) { + x = 42; + uint256 x0 = s[0]; + uint256 x1 = s[1]; + uint256 x2 = s[2]; + uint256 x3 = s[3]; + uint256 x4 = s[4]; + uint256 x5 = s[5]; + uint256 x6 = s[6]; + uint256 x7 = s[7]; + uint256 x8 = s[8]; + uint256 x9 = s[9]; + uint256 x10 = s[10]; + uint256 x11 = s[11]; + uint256 x12 = s[12]; + uint256 x13 = s[13]; + uint256 x14 = s[14]; + uint256 x15 = s[15]; + uint256 x16 = s[16]; + uint256 x17 = s[17]; + uint256 x18 = s[18]; + s[1000] = x0 + 2; + s[118] = x18; + s[117] = x17; + s[116] = x16; + s[115] = x15; + s[114] = x14; + s[113] = x13; + s[112] = x12; + s[111] = x11; + s[110] = x10; + s[109] = x9; + s[108] = x8; + s[107] = x7; + s[106] = x6; + s[105] = x5; + s[104] = x4; + s[103] = x3; + s[102] = x2; + s[101] = x1; + s[100] = x0; + } + function test() public view returns(uint256) { + return s[1000]; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 0x2a +// test() -> 2 diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol index 28d671780..8950f1ca1 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): Empty array "pop" detected here +// Warning 2529: (82-89): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol index 5567afa87..cd16d340d 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): Empty array "pop" detected here +// Warning 2529: (82-89): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol index 0cbb15ea0..ea8679afd 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol @@ -8,5 +8,5 @@ contract C { } } // ---- -// Warning 2529: (82-89): Empty array "pop" detected here -// Warning 2529: (93-100): Empty array "pop" detected here +// Warning 2529: (82-89): CHC: Empty array "pop" detected here. +// Warning 2529: (93-100): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol index 241d02c79..28f309e43 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 2529: (94-101): Empty array "pop" detected here +// Warning 2529: (94-101): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol index 6a05d3af8..0d8c689c5 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 2529: (122-129): Empty array "pop" detected here +// Warning 2529: (122-129): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol index 40e081d30..8847d29f2 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 2529: (127-134): Empty array "pop" detected here +// Warning 2529: (127-134): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol index 517755aca..4f14142b1 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol @@ -13,4 +13,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): Empty array "pop" detected here +// Warning 2529: (82-89): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_1.sol b/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_1.sol index 3312aede3..8857b91db 100644 --- a/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_1.sol +++ b/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_1.sol @@ -11,10 +11,3 @@ contract C { } } // ---- -// Warning 6328: (119-157): Assertion violation happens here -// Warning 8115: (76-80): Assertion checker does not yet support the type of this variable. -// Warning 8115: (83-87): Assertion checker does not yet support the type of this variable. -// Warning 7650: (126-132): Assertion checker does not yet support this expression. -// Warning 8364: (126-128): Assertion checker does not yet implement type struct C.S storage ref -// Warning 7650: (143-149): Assertion checker does not yet support this expression. -// Warning 8364: (143-145): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_2d_1.sol b/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_2d_1.sol index c07ab4aad..67852d556 100644 --- a/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_2d_1.sol +++ b/test/libsolidity/smtCheckerTests/array_members/length_1d_struct_array_2d_1.sol @@ -11,12 +11,3 @@ contract C { } } // ---- -// Warning 6328: (121-165): Assertion violation happens here -// Warning 8115: (78-82): Assertion checker does not yet support the type of this variable. -// Warning 8115: (85-89): Assertion checker does not yet support the type of this variable. -// Warning 7650: (128-134): Assertion checker does not yet support this expression. -// Warning 8364: (128-130): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9118: (128-137): Assertion checker does not yet implement this expression. -// Warning 7650: (148-154): Assertion checker does not yet support this expression. -// Warning 8364: (148-150): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9118: (148-157): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/array_members/length_basic.sol b/test/libsolidity/smtCheckerTests/array_members/length_basic.sol index b5f4a07d3..3426a0c6b 100644 --- a/test/libsolidity/smtCheckerTests/array_members/length_basic.sol +++ b/test/libsolidity/smtCheckerTests/array_members/length_basic.sol @@ -10,4 +10,4 @@ contract C { } } // ---- -// Warning 6328: (153-176): Assertion violation happens here +// Warning 6328: (153-176): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_2_fail.sol b/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_2_fail.sol index 741ecff3d..2472aceb6 100644 --- a/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_2_fail.sol @@ -14,6 +14,6 @@ contract C { } } // ---- -// Warning 6328: (198-224): Assertion violation happens here -// Warning 6328: (228-254): Assertion violation happens here -// Warning 6328: (258-281): Assertion violation happens here +// Warning 6328: (198-224): CHC: Assertion violation happens here. +// Warning 6328: (228-254): CHC: Assertion violation happens here. +// Warning 6328: (258-281): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_3_fail.sol b/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_3_fail.sol index eff6b2fbd..91418c910 100644 --- a/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_3_fail.sol +++ b/test/libsolidity/smtCheckerTests/array_members/length_same_after_assignment_3_fail.sol @@ -16,7 +16,7 @@ contract C { } } // ---- -// Warning 6328: (222-248): Assertion violation happens here -// Warning 6328: (252-278): Assertion violation happens here -// Warning 6328: (282-305): Assertion violation happens here -// Warning 6328: (309-335): Assertion violation happens here +// Warning 6328: (222-248): CHC: Assertion violation happens here. +// Warning 6328: (252-278): CHC: Assertion violation happens here. +// Warning 6328: (282-305): CHC: Assertion violation happens here. +// Warning 6328: (309-335): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol index 75e51df74..2073cec2e 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): Empty array "pop" detected here +// Warning 2529: (82-89): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol index 5d4bd3a97..e90a9175a 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 2529: (111-121): Empty array "pop" detected here +// Warning 2529: (111-121): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol index bb9d37c0f..e42659cde 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 2529: (76-83): Empty array "pop" detected here +// Warning 2529: (76-83): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol index ed1f8fc65..d94e3cabe 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 2529: (150-157): Empty array "pop" detected here +// Warning 2529: (150-157): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_2d_arg_1_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/push_2d_arg_1_unsafe.sol index 866cfe1eb..9d5559e78 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_2d_arg_1_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_2d_arg_1_unsafe.sol @@ -10,5 +10,5 @@ contract C { } } // ---- -// Warning 3944: (162-177): Underflow (resulting value less than 0) happens here -// Warning 6328: (150-184): Assertion violation happens here +// Warning 3944: (162-177): CHC: Underflow (resulting value less than 0) happens here. +// Warning 6328: (150-184): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_1_fail.sol b/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_1_fail.sol index 7827950d1..4ab8f23f6 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_1_fail.sol @@ -8,5 +8,5 @@ contract C { } } // ---- -// Warning 6328: (113-139): Assertion violation happens here -// Warning 6328: (143-189): Assertion violation happens here +// Warning 6328: (113-139): CHC: Assertion violation happens here. +// Warning 6328: (143-189): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_2_fail.sol b/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_2_fail.sol index cfcbbfa68..48697f548 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_push_no_args_2_fail.sol @@ -10,6 +10,6 @@ contract C { } } // ---- -// Warning 6328: (122-148): Assertion violation happens here -// Warning 6328: (202-218): Assertion violation happens here -// Warning 6328: (222-278): Assertion violation happens here +// Warning 6328: (122-148): CHC: Assertion violation happens here. +// Warning 6328: (202-218): CHC: Assertion violation happens here. +// Warning 6328: (222-278): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_safe_aliasing.sol b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_safe_aliasing.sol index 5fa9ef7d9..c402df250 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_safe_aliasing.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_safe_aliasing.sol @@ -12,5 +12,5 @@ contract C { } } // ---- -// Warning 3944: (217-232): Underflow (resulting value less than 0) happens here -// Warning 6328: (205-239): Assertion violation happens here +// Warning 3944: (217-232): CHC: Underflow (resulting value less than 0) happens here. +// Warning 6328: (205-239): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_aliasing.sol b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_aliasing.sol index 89d89c108..9849ab325 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_aliasing.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_aliasing.sol @@ -12,4 +12,4 @@ contract C { } } // ---- -// Warning 6328: (167-188): Assertion violation happens here +// Warning 6328: (167-188): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol index 61bdb3d5a..79a3fdc47 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol @@ -18,6 +18,6 @@ contract C { } } // ---- -// Warning 6328: (193-217): Assertion violation happens here -// Warning 6328: (309-333): Assertion violation happens here -// Warning 6328: (419-436): Assertion violation happens here +// Warning 6328: (193-217): CHC: Assertion violation happens here. +// Warning 6328: (309-333): CHC: Assertion violation happens here. +// Warning 6328: (419-436): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_struct_member_1.sol b/test/libsolidity/smtCheckerTests/array_members/push_struct_member_1.sol index f2c30c84d..b2e500c74 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_struct_member_1.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_struct_member_1.sol @@ -15,13 +15,3 @@ contract C { } // ---- -// Warning 8115: (72-75): Assertion checker does not yet support the type of this variable. -// Warning 8115: (100-103): Assertion checker does not yet support the type of this variable. -// Warning 7650: (130-133): Assertion checker does not yet support this expression. -// Warning 8364: (130-131): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9599: (130-133): Assertion checker does not yet implement this expression. -// Warning 7650: (144-149): Assertion checker does not yet support this expression. -// Warning 8364: (144-147): Assertion checker does not yet implement type struct C.S storage ref -// Warning 7650: (144-147): Assertion checker does not yet support this expression. -// Warning 8364: (144-145): Assertion checker does not yet implement type struct C.T storage ref -// Warning 9599: (144-149): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_struct_member_2.sol b/test/libsolidity/smtCheckerTests/array_members/push_struct_member_2.sol index a717c8d4b..ba9a84713 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_struct_member_2.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_struct_member_2.sol @@ -16,18 +16,3 @@ contract C { } // ---- -// Warning 8115: (72-75): Assertion checker does not yet support the type of this variable. -// Warning 8115: (102-105): Assertion checker does not yet support the type of this variable. -// Warning 7650: (132-135): Assertion checker does not yet support this expression. -// Warning 8364: (132-133): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9599: (132-135): Assertion checker does not yet implement this expression. -// Warning 7650: (146-149): Assertion checker does not yet support this expression. -// Warning 8364: (146-147): Assertion checker does not yet implement type struct C.T storage ref -// Warning 8364: (146-156): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9599: (146-149): Assertion checker does not yet implement this expression. -// Warning 7650: (160-168): Assertion checker does not yet support this expression. -// Warning 7650: (160-163): Assertion checker does not yet support this expression. -// Warning 8364: (160-161): Assertion checker does not yet implement type struct C.T storage ref -// Warning 8364: (160-166): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9118: (160-166): Assertion checker does not yet implement this expression. -// Warning 9599: (160-168): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_zero_2d_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/push_zero_2d_unsafe.sol index ac278a22a..7ca3db4e6 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_zero_2d_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_zero_2d_unsafe.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (111-144): Assertion violation happens here +// Warning 6328: (111-144): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_zero_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/push_zero_unsafe.sol index 504d5a95c..0e9f80342 100644 --- a/test/libsolidity/smtCheckerTests/array_members/push_zero_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/push_zero_unsafe.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6328: (94-124): Assertion violation happens here +// Warning 6328: (94-124): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/storage_pointer_push_1.sol b/test/libsolidity/smtCheckerTests/array_members/storage_pointer_push_1.sol index 721c4a8ba..fe4daf407 100644 --- a/test/libsolidity/smtCheckerTests/array_members/storage_pointer_push_1.sol +++ b/test/libsolidity/smtCheckerTests/array_members/storage_pointer_push_1.sol @@ -15,4 +15,4 @@ contract C { } } // ---- -// Warning 6328: (184-213): Assertion violation happens here +// Warning 6328: (184-213): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/complex/MerkleProof.sol b/test/libsolidity/smtCheckerTests/complex/MerkleProof.sol index 5d6d3d3cb..fb0f69ddc 100644 --- a/test/libsolidity/smtCheckerTests/complex/MerkleProof.sol +++ b/test/libsolidity/smtCheckerTests/complex/MerkleProof.sol @@ -34,7 +34,5 @@ library MerkleProof { } // ---- -// Warning 8364: (988-991): Assertion checker does not yet implement type abi // Warning 4588: (988-1032): Assertion checker does not yet implement this type of function call. -// Warning 8364: (1175-1178): Assertion checker does not yet implement type abi // Warning 4588: (1175-1219): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/complex/slither/const_state_variables.sol b/test/libsolidity/smtCheckerTests/complex/slither/const_state_variables.sol index 4e92b34eb..e7ca8a8af 100644 --- a/test/libsolidity/smtCheckerTests/complex/slither/const_state_variables.sol +++ b/test/libsolidity/smtCheckerTests/complex/slither/const_state_variables.sol @@ -53,4 +53,4 @@ contract MyConc{ // ---- // Warning 2519: (773-792): This declaration shadows an existing declaration. // Warning 2018: (1009-1086): Function state mutability can be restricted to view -// Warning 4984: (985-1002): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (985-1002): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/complex/slither/data_dependency.sol b/test/libsolidity/smtCheckerTests/complex/slither/data_dependency.sol index 6fc041fb1..074bc5b10 100644 --- a/test/libsolidity/smtCheckerTests/complex/slither/data_dependency.sol +++ b/test/libsolidity/smtCheckerTests/complex/slither/data_dependency.sol @@ -118,23 +118,3 @@ contract PropagateThroughReturnValue { } // ---- // Warning 2018: (1879-1947): Function state mutability can be restricted to view -// Warning 8115: (318-332): Assertion checker does not yet support the type of this variable. -// Warning 8115: (338-347): Assertion checker does not yet support the type of this variable. -// Warning 8115: (353-378): Assertion checker does not yet support the type of this variable. -// Warning 8115: (384-409): Assertion checker does not yet support the type of this variable. -// Warning 7650: (464-479): Assertion checker does not yet support this expression. -// Warning 8364: (464-475): Assertion checker does not yet implement type struct Reference.St storage ref -// Warning 8182: (464-494): Assertion checker does not yet implement such assignments. -// Warning 7650: (539-554): Assertion checker does not yet support this expression. -// Warning 8364: (539-550): Assertion checker does not yet implement type struct Reference.St storage ref -// Warning 7650: (557-567): Assertion checker does not yet support this expression. -// Warning 8364: (557-563): Assertion checker does not yet implement type struct Reference.St storage ref -// Warning 8182: (539-567): Assertion checker does not yet implement such assignments. -// Warning 8115: (629-643): Assertion checker does not yet support the type of this variable. -// Warning 8364: (646-668): Assertion checker does not yet implement type struct Reference.St storage ref -// Warning 8364: (700-703): Assertion checker does not yet implement type struct Reference.St storage pointer -// Warning 8364: (706-728): Assertion checker does not yet implement type struct Reference.St storage ref -// Warning 8364: (700-728): Assertion checker does not yet implement type struct Reference.St storage pointer -// Warning 7650: (748-755): Assertion checker does not yet support this expression. -// Warning 8364: (748-751): Assertion checker does not yet implement type struct Reference.St storage pointer -// Warning 8182: (748-770): Assertion checker does not yet implement such assignments. diff --git a/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol b/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol index 885200cf5..daecc82dc 100644 --- a/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol +++ b/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol @@ -83,7 +83,6 @@ contract InternalCall { // Warning 2018: (1144-1206): Function state mutability can be restricted to pure // Warning 2018: (1212-1274): Function state mutability can be restricted to pure // Warning 2018: (1280-1342): Function state mutability can be restricted to pure -// Warning 8364: (771-774): Assertion checker does not yet implement type abi // Warning 5084: (782-813): Type conversion is not yet fully supported and might yield false positives. // Warning 4588: (771-814): Assertion checker does not yet implement this type of function call. // Warning 5729: (1403-1408): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol b/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol index 287e7e8f6..0bbf08c56 100644 --- a/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol +++ b/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol @@ -8,7 +8,5 @@ contract C { } // ---- // Warning 2072: (133-143): Unused local variable. -// Warning 8115: (133-143): Assertion checker does not yet support the type of this variable. // Warning 8364: (146-147): Assertion checker does not yet implement type type(struct C.A storage pointer) -// Warning 8364: (146-163): Assertion checker does not yet implement type struct C.A memory // Warning 4639: (146-163): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch.sol index fc54d5a01..c32bdd983 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch.sol @@ -15,6 +15,3 @@ contract C } } // ---- -// Warning 5084: (208-218): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (123-133): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (208-218): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_2.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_2.sol index 0114ab988..1bff12f86 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_2.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_2.sol @@ -20,8 +20,3 @@ contract C } } // ---- -// Warning 5084: (271-281): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (123-133): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (271-281): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (186-196): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (271-281): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_3.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_3.sol index f00035905..d14a2e6bc 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_3.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_3.sol @@ -20,8 +20,3 @@ contract C } } // ---- -// Warning 5084: (275-285): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (123-133): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (275-285): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (189-199): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (275-285): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_4.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_4.sol index e8f08cc3e..bdb7b9fd8 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_4.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_branch_4.sol @@ -25,7 +25,3 @@ contract C } // ---- -// Warning 5084: (275-285): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (123-133): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (189-199): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (275-285): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_else_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_else_branch.sol index 23ba4ff05..8c3099bf1 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_else_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_else_branch.sol @@ -16,6 +16,3 @@ contract C } } // ---- -// Warning 5084: (219-229): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (134-144): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (219-229): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_modifier_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_modifier_branch.sol index 755d44ff6..f79be2298 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_modifier_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_modifier_branch.sol @@ -19,6 +19,3 @@ contract C } } // ---- -// Warning 5084: (249-259): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (118-128): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (249-259): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_placeholder_inside_modifier_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_placeholder_inside_modifier_branch.sol index e8d22edcf..5366b22d4 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_placeholder_inside_modifier_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/function_call_inside_placeholder_inside_modifier_branch.sol @@ -20,6 +20,3 @@ contract C } } // ---- -// Warning 5084: (247-257): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (162-172): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (247-257): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/control_flow/require.sol b/test/libsolidity/smtCheckerTests/control_flow/require.sol new file mode 100644 index 000000000..1a63691b4 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/require.sol @@ -0,0 +1,33 @@ +pragma experimental SMTChecker; + +contract C { + function f() pure public { + require(false); + // This is not reachable. + assert(false); + } + + function g() pure public { + require(false, "require message"); + // This is not reachable. + assert(false); + } + + function h(bool b) pure public { + if (b) + require(false); + assert(!b); + } + + // Check that arguments are evaluated. + bool x = false; + function m() view internal returns (string memory) { + assert(x != true); + } + function i() public { + x = true; + require(false, m()); + } +} +// ---- +// Warning 6328: (448-465): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/revert.sol b/test/libsolidity/smtCheckerTests/control_flow/revert.sol new file mode 100644 index 000000000..50e9e09a8 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/revert.sol @@ -0,0 +1,35 @@ +pragma experimental SMTChecker; + +contract C { + function f() pure public { + revert(); + // This is not reachable. + assert(false); + } + + function g() pure public { + revert("revert message"); + // This is not reachable. + assert(false); + } + + function h(bool b) pure public { + if (b) + revert(); + assert(!b); + } + + // Check that arguments are evaluated. + bool x = false; + function m() view internal returns (string memory) { + assert(x != true); + } + function i() public { + x = true; + revert(m()); + } +} +// ---- +// Warning 5740: (116-129): Unreachable code. +// Warning 5740: (221-234): Unreachable code. +// Warning 6328: (427-444): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/revert_complex_flow.sol b/test/libsolidity/smtCheckerTests/control_flow/revert_complex_flow.sol new file mode 100644 index 000000000..5c4b74e13 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/revert_complex_flow.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; + +contract C { + function f(bool b, uint a) pure public { + require(a <= 256); + if (b) + revert(); + uint c = a + 1; + if (b) + c--; + else + c++; + assert(c == a); + } +} +// ---- +// Warning 6328: (183-197): CHC: Assertion violation happens here. +// Warning 6838: (155-156): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_fail.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_fail.sol index 650bce10a..d4aef2c83 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_fail.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_fail.sol @@ -15,4 +15,4 @@ contract c { } } // ---- -// Warning 6328: (227-236): Assertion violation happens here +// Warning 6328: (227-236): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol index 77e2f247f..14023d2c7 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol @@ -17,5 +17,5 @@ contract c { } } // ---- -// Warning 6328: (202-218): Assertion violation happens here -// Warning 6328: (242-252): Assertion violation happens here +// Warning 6328: (202-218): CHC: Assertion violation happens here. +// Warning 6328: (242-252): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_need_both_fail.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_need_both_fail.sol index bc9c800af..81cb5c820 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_need_both_fail.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_need_both_fail.sol @@ -15,4 +15,4 @@ contract c { } } // ---- -// Warning 6328: (225-235): Assertion violation happens here +// Warning 6328: (225-235): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched.sol index c596f4f90..d4b50a29e 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched.sol @@ -12,8 +12,8 @@ contract C } } // ---- -// Warning 6838: (84-110): Condition is always false. -// Warning 6838: (121-147): Condition is always true. -// Warning 6838: (158-183): Condition is always false. -// Warning 6838: (194-221): Condition is always false. -// Warning 6838: (232-247): Condition is always true. +// Warning 6838: (84-110): BMC: Condition is always false. +// Warning 6838: (121-147): BMC: Condition is always true. +// Warning 6838: (158-183): BMC: Condition is always false. +// Warning 6838: (194-221): BMC: Condition is always false. +// Warning 6838: (232-247): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched_function.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched_function.sol index 127ebfcce..cf4424d5a 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched_function.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_touched_function.sol @@ -16,8 +16,8 @@ contract C } } // ---- -// Warning 6838: (156-179): Condition is always false. -// Warning 6838: (190-213): Condition is always true. -// Warning 6838: (224-243): Condition is always false. -// Warning 6838: (254-277): Condition is always false. -// Warning 6838: (288-300): Condition is always true. +// Warning 6838: (156-179): BMC: Condition is always false. +// Warning 6838: (190-213): BMC: Condition is always true. +// Warning 6838: (224-243): BMC: Condition is always false. +// Warning 6838: (254-277): BMC: Condition is always false. +// Warning 6838: (288-300): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_fail.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_fail.sol index 6640e399c..07bee8ab7 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_fail.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_fail.sol @@ -15,4 +15,4 @@ contract c { } } // ---- -// Warning 6328: (225-235): Assertion violation happens here +// Warning 6328: (225-235): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_inside_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_inside_branch.sol index 77ec37ebd..ead105285 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_inside_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_inside_branch.sol @@ -24,4 +24,4 @@ contract c { } } // ---- -// Warning 6328: (360-370): Assertion violation happens here +// Warning 6328: (360-370): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_need_both_fail.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_need_both_fail.sol index 6615651fd..e60c94d86 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_need_both_fail.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_need_both_fail.sol @@ -15,4 +15,4 @@ contract c { } } // ---- -// Warning 6328: (225-235): Assertion violation happens here +// Warning 6328: (225-235): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched.sol index e629b188c..c5d9bb08d 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched.sol @@ -12,8 +12,8 @@ contract C } } // ---- -// Warning 6838: (84-110): Condition is always true. -// Warning 6838: (121-147): Condition is always true. -// Warning 6838: (158-183): Condition is always true. -// Warning 6838: (194-221): Condition is always true. -// Warning 6838: (232-248): Condition is always false. +// Warning 6838: (84-110): BMC: Condition is always true. +// Warning 6838: (121-147): BMC: Condition is always true. +// Warning 6838: (158-183): BMC: Condition is always true. +// Warning 6838: (194-221): BMC: Condition is always true. +// Warning 6838: (232-248): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched_function.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched_function.sol index 3ec6a53db..c97365981 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched_function.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_or_touched_function.sol @@ -16,8 +16,8 @@ contract C } } // ---- -// Warning 6838: (156-179): Condition is always true. -// Warning 6838: (190-213): Condition is always true. -// Warning 6838: (224-243): Condition is always true. -// Warning 6838: (254-277): Condition is always true. -// Warning 6838: (288-301): Condition is always false. +// Warning 6838: (156-179): BMC: Condition is always true. +// Warning 6838: (190-213): BMC: Condition is always true. +// Warning 6838: (224-243): BMC: Condition is always true. +// Warning 6838: (254-277): BMC: Condition is always true. +// Warning 6838: (288-301): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol index 37adaa0d3..70c8eb1f6 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (159-173): Assertion violation happens here +// Warning 6328: (159-173): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol index 44124a100..dc051dad3 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (159-173): Assertion violation happens here +// Warning 6328: (159-173): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol index 2369aa5a9..0faff5b29 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (161-175): Assertion violation happens here +// Warning 6328: (161-175): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external.sol b/test/libsolidity/smtCheckerTests/external_calls/external.sol index 7e14fa927..b34eeae96 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external.sol @@ -17,4 +17,4 @@ contract C { } } // ---- -// Warning 6328: (200-214): Assertion violation happens here +// Warning 6328: (200-214): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash.sol index 322af8129..45df8282e 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash.sol @@ -26,4 +26,4 @@ contract C { } } // ---- -// Warning 6328: (423-445): Assertion violation happens here +// Warning 6328: (423-445): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_pure.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_pure.sol index 510950f41..5e6f18f27 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_pure.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_pure.sol @@ -28,4 +28,4 @@ contract C { } } // ---- -// Warning 6328: (431-453): Assertion violation happens here +// Warning 6328: (431-453): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol index cd24a87fd..eb0e64777 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol @@ -34,5 +34,4 @@ contract C { } } // ---- -// Warning 6328: (528-565): Assertion violation happens here -// Warning 5084: (544-554): Type conversion is not yet fully supported and might yield false positives. +// Warning 6328: (528-565): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy.sol index fd2198fe5..3c5da807c 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy.sol @@ -29,4 +29,4 @@ contract C { } } // ---- -// Warning 6328: (299-313): Assertion violation happens here +// Warning 6328: (299-313): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol index 698a6c647..5f7e68b45 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol @@ -42,6 +42,5 @@ contract C { } } // ---- -// Warning 6328: (452-466): Assertion violation happens here -// Warning 6328: (470-496): Assertion violation happens here -// Warning 5084: (92-102): Type conversion is not yet fully supported and might yield false positives. +// Warning 6328: (452-466): CHC: Assertion violation happens here. +// Warning 6328: (470-496): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_unsafe.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_unsafe.sol index 74c71e398..355fdbd8b 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_unsafe.sol @@ -34,6 +34,5 @@ contract C { } } // ---- -// Warning 6328: (381-395): Assertion violation happens here -// Warning 6328: (399-425): Assertion violation happens here -// Warning 5084: (116-126): Type conversion is not yet fully supported and might yield false positives. +// Warning 6328: (381-395): CHC: Assertion violation happens here. +// Warning 6328: (399-425): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_unsafe.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_unsafe.sol index c37614fd6..d1511e569 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_unsafe.sol @@ -38,6 +38,5 @@ contract C { } } // ---- -// Warning 6328: (435-461): Assertion violation happens here -// Warning 6328: (594-631): Assertion violation happens here -// Warning 5084: (610-620): Type conversion is not yet fully supported and might yield false positives. +// Warning 6328: (435-461): CHC: Assertion violation happens here. +// Warning 6328: (594-631): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_inc.sol b/test/libsolidity/smtCheckerTests/external_calls/external_inc.sol index 38b588463..e0e66ad67 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_inc.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_inc.sol @@ -18,5 +18,5 @@ contract C { } } // ---- -// Warning 6328: (189-203): Assertion violation happens here -// Warning 2661: (146-149): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 6328: (189-203): CHC: Assertion violation happens here. +// Warning 2661: (146-149): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_inc1_inc2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_inc1_inc2.sol index e96f8b279..a8d694864 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_inc1_inc2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_inc1_inc2.sol @@ -25,4 +25,4 @@ contract C { } } // ---- -// Warning 6328: (286-303): Assertion violation happens here +// Warning 6328: (286-303): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_single_inc.sol b/test/libsolidity/smtCheckerTests/external_calls/external_single_inc.sol index a6e4917cc..e4473c567 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_single_inc.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_single_inc.sol @@ -23,4 +23,4 @@ contract C { } } // ---- -// Warning 6328: (256-273): Assertion violation happens here +// Warning 6328: (256-273): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/mutex_f_no_guard.sol b/test/libsolidity/smtCheckerTests/external_calls/mutex_f_no_guard.sol index 22e9d53f3..5f2132898 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/mutex_f_no_guard.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/mutex_f_no_guard.sol @@ -27,4 +27,4 @@ contract C { } } // ---- -// Warning 6328: (307-321): Assertion violation happens here +// Warning 6328: (307-321): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/abi_encode_functions.sol b/test/libsolidity/smtCheckerTests/functions/abi_encode_functions.sol index d03cd4bb5..2cf037ea5 100644 --- a/test/libsolidity/smtCheckerTests/functions/abi_encode_functions.sol +++ b/test/libsolidity/smtCheckerTests/functions/abi_encode_functions.sol @@ -5,7 +5,5 @@ contract C { } } // ---- -// Warning 8364: (162-165): Assertion checker does not yet implement type abi // Warning 4588: (162-176): Assertion checker does not yet implement this type of function call. -// Warning 8364: (178-181): Assertion checker does not yet implement type abi // Warning 4588: (178-203): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy.sol index f2d408cd6..82250de96 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy.sol @@ -13,4 +13,4 @@ contract A is C { } } // ---- -// Warning 6328: (152-166): Assertion violation happens here +// Warning 6328: (152-166): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_2.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_2.sol index 88c7722e4..aeb1aefcf 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_2.sol @@ -4,4 +4,4 @@ contract A is C { constructor() C(2) { assert(a == 2); } } contract B is C { constructor() C(3) { assert(a == 3); } } contract J is C { constructor() C(3) { assert(a == 4); } } // ---- -// Warning 6328: (243-257): Assertion violation happens here +// Warning 6328: (243-257): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol index 789b98368..7a90d2cfb 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol @@ -19,6 +19,6 @@ contract A is B { } } // ---- -// Warning 4984: (203-208): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (244-249): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (232-250): Assertion violation happens here +// Warning 4984: (203-208): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (244-249): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (232-250): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol index 6e8c4fe95..69e2233ee 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol @@ -18,6 +18,6 @@ contract A is B { } } // ---- -// Warning 4984: (198-203): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (207-212): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (230-235): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (198-203): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (207-212): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (230-235): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol index e5c8d5b38..ad8789a94 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol @@ -25,6 +25,6 @@ contract A is B2, B1 { } } // ---- -// Warning 4984: (200-205): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (314-319): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (302-320): Assertion violation happens here +// Warning 4984: (200-205): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (314-319): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (302-320): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol index b09b836ec..b35d268e2 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol @@ -25,6 +25,6 @@ contract A is B2, B1 { } } // ---- -// Warning 4984: (200-205): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (314-319): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (302-320): Assertion violation happens here +// Warning 4984: (200-205): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (314-319): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (302-320): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol index f6bfc6d94..1a9cdbdce 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol @@ -27,7 +27,7 @@ contract A is B2, B1 { } } // ---- -// Warning 4984: (160-165): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (225-230): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (241-246): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (334-350): Assertion violation happens here +// Warning 4984: (160-165): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (225-230): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (241-246): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (334-350): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_empty_middle.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_empty_middle.sol index 64f0482f8..9c061859d 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_empty_middle.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_empty_middle.sol @@ -20,4 +20,4 @@ contract A is B, B2 { } // ---- // Warning 5667: (164-170): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (194-208): Assertion violation happens here +// Warning 6328: (194-208): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_chain.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_chain.sol index d694b191a..c930a45ec 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_chain.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_chain.sol @@ -19,4 +19,4 @@ contract A is B { } // ---- // Warning 5667: (194-200): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (224-238): Assertion violation happens here +// Warning 6328: (224-238): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle.sol index c89cad884..caaf7fbca 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle.sol @@ -17,4 +17,4 @@ contract A is B { } // ---- // Warning 5667: (138-144): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (172-186): Assertion violation happens here +// Warning 6328: (172-186): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle_no_invocation.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle_no_invocation.sol index a5ac97344..f208ec8d0 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle_no_invocation.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_empty_middle_no_invocation.sol @@ -16,4 +16,4 @@ contract A is B { } // ---- // Warning 5667: (138-144): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (150-164): Assertion violation happens here +// Warning 6328: (150-164): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain.sol index a5962165a..289cfbd76 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain.sol @@ -27,4 +27,4 @@ contract A is B { } // ---- // Warning 5667: (254-260): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (284-298): Assertion violation happens here +// Warning 6328: (284-298): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_local_vars.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_local_vars.sol index 72f849db3..00e581d07 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_local_vars.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_local_vars.sol @@ -32,4 +32,4 @@ contract A is B { } // ---- // Warning 5667: (296-302): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (357-372): Assertion violation happens here +// Warning 6328: (357-372): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol index 92e53f40c..92606cbca 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol @@ -25,5 +25,5 @@ contract A is B { } } // ---- -// Warning 4984: (247-252): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (328-342): Assertion violation happens here +// Warning 4984: (247-252): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (328-342): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params_2.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params_2.sol index 685be3b96..bb2f93747 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params_2.sol @@ -23,4 +23,4 @@ contract B is C { contract A is B { } // ---- -// Warning 6328: (266-280): Assertion violation happens here +// Warning 6328: (266-280): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_modifier.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_modifier.sol index 8a67b7a8b..451a1c2a0 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_modifier.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_modifier.sol @@ -14,4 +14,4 @@ contract A is C { } } // ---- -// Warning 6328: (188-202): Assertion violation happens here +// Warning 6328: (188-202): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol index f91439b77..4dc2d368d 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol @@ -13,5 +13,5 @@ contract A is C { } } // ---- -// Warning 6328: (134-148): Assertion violation happens here -// Warning 6328: (152-168): Assertion violation happens here +// Warning 6328: (134-148): CHC: Assertion violation happens here. +// Warning 6328: (152-168): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_simple.sol b/test/libsolidity/smtCheckerTests/functions/constructor_simple.sol index 79fbb2714..2cdf9eca7 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_simple.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_simple.sol @@ -13,4 +13,4 @@ contract C { } } // ---- -// Warning 6328: (141-155): Assertion violation happens here +// Warning 6328: (141-155): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_state_value.sol b/test/libsolidity/smtCheckerTests/functions/constructor_state_value.sol index e674dc70d..4f539e8a6 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_state_value.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_state_value.sol @@ -13,4 +13,4 @@ contract C { } } // ---- -// Warning 6328: (145-159): Assertion violation happens here +// Warning 6328: (145-159): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_state_value_inherited.sol b/test/libsolidity/smtCheckerTests/functions/constructor_state_value_inherited.sol index e3b765264..752286497 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_state_value_inherited.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_state_value_inherited.sol @@ -15,4 +15,4 @@ contract C is B { } } // ---- -// Warning 6328: (165-179): Assertion violation happens here +// Warning 6328: (165-179): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol b/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol index 6771f6a05..4da5ff525 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol @@ -13,5 +13,5 @@ contract C { } } // ---- -// Warning 4984: (115-120): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (162-176): Assertion violation happens here +// Warning 4984: (115-120): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (162-176): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/function_call_state_var_init.sol b/test/libsolidity/smtCheckerTests/functions/function_call_state_var_init.sol index ba8b2638e..233022784 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_call_state_var_init.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_call_state_var_init.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (116-132): Assertion violation happens here +// Warning 6328: (116-132): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_1.sol b/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_1.sol index f32cfa4fa..8b8ceed1a 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_1.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_1.sol @@ -13,4 +13,3 @@ contract C { } } // ---- -// Warning 5084: (198-208): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_2.sol b/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_2.sol index 06dc94cce..897367d48 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_external_call_should_not_inline_2.sol @@ -13,4 +13,3 @@ contract C { } } // ---- -// Warning 5084: (107-117): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var.sol b/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var.sol index db3e7918c..6b94ea0c3 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var.sol @@ -16,4 +16,4 @@ contract C } } // ---- -// Warning 6328: (209-223): Assertion violation happens here +// Warning 6328: (209-223): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var_3.sol b/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var_3.sol index 9a1aac540..21bfa18ad 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var_3.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_inside_branch_modify_state_var_3.sol @@ -24,5 +24,5 @@ contract C } // ---- -// Warning 6328: (209-223): Assertion violation happens here -// Warning 6328: (321-335): Assertion violation happens here +// Warning 6328: (209-223): CHC: Assertion violation happens here. +// Warning 6328: (321-335): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_bound_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_bound_1_fail.sol index 5c4d16cfd..1bc8ed85b 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_bound_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_bound_1_fail.sol @@ -18,4 +18,4 @@ contract C } } // ---- -// Warning 6328: (261-277): Assertion violation happens here +// Warning 6328: (261-277): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol b/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol index 8da1b5e16..5ac741522 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol @@ -17,4 +17,4 @@ contract C } } // ---- -// Warning 4661: (297-321): Assertion violation happens here +// Warning 4661: (297-321): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_external_4.sol b/test/libsolidity/smtCheckerTests/functions/functions_external_4.sol index c75214b4f..7859523be 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_external_4.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_external_4.sol @@ -16,4 +16,4 @@ contract D } } // ---- -// Warning 6328: (191-206): Assertion violation happens here +// Warning 6328: (191-206): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_identity_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_identity_1_fail.sol index 4931b8fec..38a57e3b7 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_identity_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_identity_1_fail.sol @@ -12,4 +12,4 @@ contract C } // ---- -// Warning 6328: (161-174): Assertion violation happens here +// Warning 6328: (161-174): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_identity_2_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_identity_2_fail.sol index 29b422c7d..ddfa6c054 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_identity_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_identity_2_fail.sol @@ -16,4 +16,4 @@ contract C } // ---- -// Warning 6328: (229-242): Assertion violation happens here +// Warning 6328: (229-242): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_identity_as_tuple_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_identity_as_tuple_fail.sol index 87a027a9c..f1a9bda36 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_identity_as_tuple_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_identity_as_tuple_fail.sol @@ -12,4 +12,4 @@ contract C } // ---- -// Warning 6328: (163-176): Assertion violation happens here +// Warning 6328: (163-176): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_library_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_library_1_fail.sol index 3c35898a2..c139a2386 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_library_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_library_1_fail.sol @@ -17,5 +17,5 @@ contract C } } // ---- -// Warning 6328: (245-261): Assertion violation happens here +// Warning 6328: (245-261): CHC: Assertion violation happens here. // Warning 8364: (228-229): Assertion checker does not yet implement type type(library L) diff --git a/test/libsolidity/smtCheckerTests/functions/functions_storage_var_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_storage_var_1_fail.sol index 93fa49176..bb6181a75 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_storage_var_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_storage_var_1_fail.sol @@ -13,4 +13,4 @@ contract C } // ---- -// Warning 6328: (144-157): Assertion violation happens here +// Warning 6328: (144-157): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_storage_var_2_fail.sol b/test/libsolidity/smtCheckerTests/functions/functions_storage_var_2_fail.sol index 5a7920122..517176612 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_storage_var_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_storage_var_2_fail.sol @@ -14,4 +14,4 @@ contract C } // ---- -// Warning 6328: (152-165): Assertion violation happens here +// Warning 6328: (152-165): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_for.sol b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_for.sol index ff2c68ef5..23b6cf8b4 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_for.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_for.sol @@ -5,4 +5,4 @@ contract C function f(bool x) public pure { require(x); for (;x;) {} } } // ---- -// Warning 6838: (98-99): Condition is always true. +// Warning 6838: (98-99): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_if.sol b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_if.sol index 619b0d5f8..ea2093fa4 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_if.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_if.sol @@ -4,4 +4,4 @@ contract C function f(bool x) public pure { require(x); if (x) {} } } // ---- -// Warning 6838: (95-96): Condition is always true. +// Warning 6838: (95-96): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_require.sol b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_require.sol index 86dfba66d..460b7da79 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_require.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_require.sol @@ -5,4 +5,4 @@ contract C function f(bool x) public pure { x = true; require(x); } } // ---- -// Warning 6838: (98-99): Condition is always true. +// Warning 6838: (98-99): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_while.sol b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_while.sol index 3ba28289d..3899d35d7 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_while.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_trivial_condition_while.sol @@ -5,4 +5,4 @@ contract C function f(bool x) public pure { require(x); while (x) {} } } // ---- -// Warning 6838: (99-100): Condition is always true. +// Warning 6838: (99-100): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance.sol index fe2e882a0..ddad55554 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance.sol @@ -17,4 +17,4 @@ contract A is B { } } // ---- -// Warning 6328: (254-268): Assertion violation happens here +// Warning 6328: (254-268): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance_2.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance_2.sol index c57fd1073..c15affa5c 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_inheritance_2.sol @@ -21,4 +21,4 @@ contract A is B { } } // ---- -// Warning 6328: (274-288): Assertion violation happens here +// Warning 6328: (274-288): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol index 05d965aa3..dba4f11ee 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol @@ -21,5 +21,5 @@ contract C{ } // ---- // Warning 5667: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 2661: (156-159): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4144: (238-241): Underflow (resulting value less than 0) happens here +// Warning 2661: (156-159): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (238-241): BMC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol index 33fc53e4f..ffd6fe24a 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol @@ -21,10 +21,10 @@ contract C{ } // ---- // Warning 5667: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (138-152): Assertion violation happens here -// Warning 6328: (170-184): Assertion violation happens here -// Warning 6328: (220-234): Assertion violation happens here -// Warning 6328: (245-259): Assertion violation happens here -// Warning 6328: (82-96): Assertion violation happens here -// Warning 2661: (156-159): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4144: (238-241): Underflow (resulting value less than 0) happens here +// Warning 6328: (138-152): CHC: Assertion violation happens here. +// Warning 6328: (170-184): CHC: Assertion violation happens here. +// Warning 6328: (220-234): CHC: Assertion violation happens here. +// Warning 6328: (245-259): CHC: Assertion violation happens here. +// Warning 6328: (82-96): CHC: Assertion violation happens here. +// Warning 2661: (156-159): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (238-241): BMC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol index 067ce603b..19a1ceb2f 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol @@ -17,5 +17,5 @@ contract C is A { } } // ---- -// Warning 4144: (100-103): Underflow (resulting value less than 0) happens here -// Warning 4144: (100-103): Underflow (resulting value less than 0) happens here +// Warning 4144: (100-103): BMC: Underflow (resulting value less than 0) happens here. +// Warning 4144: (100-103): BMC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol index d07c11465..ad6d84ed6 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol @@ -17,8 +17,8 @@ contract C is A { } } // ---- -// Warning 6328: (82-96): Assertion violation happens here -// Warning 6328: (148-162): Assertion violation happens here -// Warning 6328: (180-194): Assertion violation happens here -// Warning 4144: (100-103): Underflow (resulting value less than 0) happens here -// Warning 4144: (100-103): Underflow (resulting value less than 0) happens here +// Warning 6328: (82-96): CHC: Assertion violation happens here. +// Warning 6328: (148-162): CHC: Assertion violation happens here. +// Warning 6328: (180-194): CHC: Assertion violation happens here. +// Warning 4144: (100-103): BMC: Underflow (resulting value less than 0) happens here. +// Warning 4144: (100-103): BMC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol index f8ec40ab7..ffb9d48cd 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol @@ -21,7 +21,7 @@ contract C{ } // ---- // Warning 5667: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 2661: (156-159): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 2661: (163-166): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 2661: (234-237): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4144: (234-237): Underflow (resulting value less than 0) happens here +// Warning 2661: (156-159): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 2661: (163-166): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 2661: (234-237): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (234-237): BMC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol index 2c8647289..3afe27b2d 100644 --- a/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol @@ -21,10 +21,10 @@ contract C{ } // ---- // Warning 5667: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (138-152): Assertion violation happens here -// Warning 6328: (184-198): Assertion violation happens here -// Warning 6328: (82-96): Assertion violation happens here -// Warning 2661: (156-159): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 2661: (163-166): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 2661: (234-237): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4144: (234-237): Underflow (resulting value less than 0) happens here +// Warning 6328: (138-152): CHC: Assertion violation happens here. +// Warning 6328: (184-198): CHC: Assertion violation happens here. +// Warning 6328: (82-96): CHC: Assertion violation happens here. +// Warning 2661: (156-159): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 2661: (163-166): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 2661: (234-237): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (234-237): BMC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/library_constant.sol b/test/libsolidity/smtCheckerTests/functions/library_constant.sol index 2a72c5216..301f0a6be 100644 --- a/test/libsolidity/smtCheckerTests/functions/library_constant.sol +++ b/test/libsolidity/smtCheckerTests/functions/library_constant.sol @@ -19,7 +19,7 @@ contract C { } } // ---- -// Warning 6328: (136-155): Assertion violation happens here -// Warning 4984: (229-234): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (327-332): Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (136-155): CHC: Assertion violation happens here. +// Warning 4984: (229-234): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (327-332): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 8364: (300-302): Assertion checker does not yet implement type type(library l1) diff --git a/test/libsolidity/smtCheckerTests/functions/this_external_call.sol b/test/libsolidity/smtCheckerTests/functions/this_external_call.sol index 384281e8e..489d7f44e 100644 --- a/test/libsolidity/smtCheckerTests/functions/this_external_call.sol +++ b/test/libsolidity/smtCheckerTests/functions/this_external_call.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (227-243): Assertion violation happens here +// Warning 6328: (227-243): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/this_external_call_return.sol b/test/libsolidity/smtCheckerTests/functions/this_external_call_return.sol index b43b95e79..0307490dc 100644 --- a/test/libsolidity/smtCheckerTests/functions/this_external_call_return.sol +++ b/test/libsolidity/smtCheckerTests/functions/this_external_call_return.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6328: (263-279): Assertion violation happens here +// Warning 6328: (263-279): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/this_fake.sol b/test/libsolidity/smtCheckerTests/functions/this_fake.sol index 2227e9b3f..259ff2d21 100644 --- a/test/libsolidity/smtCheckerTests/functions/this_fake.sol +++ b/test/libsolidity/smtCheckerTests/functions/this_fake.sol @@ -21,4 +21,4 @@ contract C } // ---- // Warning 2319: (160-166): This declaration shadows a builtin symbol. -// Warning 6328: (268-282): Assertion violation happens here +// Warning 6328: (268-282): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/this_state.sol b/test/libsolidity/smtCheckerTests/functions/this_state.sol index b21c71972..7cef58b3e 100644 --- a/test/libsolidity/smtCheckerTests/functions/this_state.sol +++ b/test/libsolidity/smtCheckerTests/functions/this_state.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (186-200): Assertion violation happens here +// Warning 6328: (186-200): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/import_base.sol b/test/libsolidity/smtCheckerTests/imports/import_base.sol new file mode 100644 index 000000000..eca0249c2 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/import_base.sol @@ -0,0 +1,24 @@ +==== Source: base ==== +contract Base { + uint x; + address a; + function f() internal returns (uint) { + a = address(this); + ++x; + return 2; + } +} +==== Source: der ==== +pragma experimental SMTChecker; +import "base"; +contract Der is Base { + function g(uint y) public { + x += f(); + assert(y > x); + } +} +// ---- +// Warning 6328: (der:113-126): CHC: Assertion violation happens here. +// Warning 2661: (base:100-103): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 2661: (der:101-109): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 2661: (base:100-103): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/import_library.sol b/test/libsolidity/smtCheckerTests/imports/import_library.sol new file mode 100644 index 000000000..852eec4f5 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/import_library.sol @@ -0,0 +1,19 @@ +==== Source: c ==== +pragma experimental SMTChecker; +import "lib"; +contract C { + function g(uint x) public pure { + uint y = L.f(); + assert(x > y); + } +} +==== Source: lib ==== +library L { + uint constant one = 1; + function f() internal pure returns (uint) { + return one; + } +} +// ---- +// Warning 6328: (c:113-126): CHC: Assertion violation happens here. +// Warning 8364: (c:104-105): Assertion checker does not yet implement type type(library L) diff --git a/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol b/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol new file mode 100644 index 000000000..27fcf8413 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol @@ -0,0 +1,25 @@ +==== Source: ==== +import "B.sol"; +pragma experimental SMTChecker; +contract C is B { + function h(uint _x) public view { + assert(_x < x); + } +} +==== Source: A.sol ==== +contract A { + uint x; + function f(uint _x) public { + x = _x; + } +} +==== Source: B.sol ==== +import "A.sol"; +contract B is A { + function g(uint _x) public view { + assert(_x > x); + } +} +// ---- +// Warning 6328: (103-117): CHC: Assertion violation happens here. +// Warning 6328: (B.sol:71-85): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/imported_fail_2.sol b/test/libsolidity/smtCheckerTests/imports/imported_fail_2.sol new file mode 100644 index 000000000..90e013c61 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/imported_fail_2.sol @@ -0,0 +1,27 @@ +==== Source: ==== +import "B.sol"; +pragma experimental SMTChecker; +contract C is B { + function h(uint _x) public view { + assert(_x < x); + } +} +==== Source: A.sol ==== +contract A { + uint x; + function f(uint _x) public { + x = _x; + } +} +==== Source: B.sol ==== +import "A.sol"; +pragma experimental SMTChecker; +contract B is A { + function g(uint _x) public view { + assert(_x > x); + } +} +// ---- +// Warning 6328: (B.sol:103-117): CHC: Assertion violation happens here. +// Warning 6328: (103-117): CHC: Assertion violation happens here. +// Warning 6328: (B.sol:103-117): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/imported_fail_3.sol b/test/libsolidity/smtCheckerTests/imports/imported_fail_3.sol new file mode 100644 index 000000000..0eca10293 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/imported_fail_3.sol @@ -0,0 +1,26 @@ +==== Source: ==== +import "A.sol"; +pragma experimental SMTChecker; +contract C is A { + function h(uint _x) public view { + assert(_x < x); + } +} +==== Source: A.sol ==== +contract A { + uint x; + function f(uint _x) public { + x = _x; + } +} +==== Source: B.sol ==== +import "A.sol"; +pragma experimental SMTChecker; +contract B is A { + function g(uint _x) public view { + assert(_x > x); + } +} +// ---- +// Warning 6328: (103-117): CHC: Assertion violation happens here. +// Warning 6328: (B.sol:103-117): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/simple.sol b/test/libsolidity/smtCheckerTests/imports/simple.sol new file mode 100644 index 000000000..5bae07210 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/simple.sol @@ -0,0 +1,6 @@ +==== Source: A.sol ==== +contract A { function f() public {} } +==== Source:==== +import "A.sol"; +pragma experimental SMTChecker; +contract C is A {} diff --git a/test/libsolidity/smtCheckerTests/imports/simple_imported_fail_no_pragma.sol b/test/libsolidity/smtCheckerTests/imports/simple_imported_fail_no_pragma.sol new file mode 100644 index 000000000..b4160f24e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/simple_imported_fail_no_pragma.sol @@ -0,0 +1,12 @@ +==== Source: ==== +import "A.sol"; +pragma experimental SMTChecker; +contract C is A {} +==== Source: A.sol ==== +contract A { + function f(uint x) public pure { + assert(x > 0); + } +} +// ---- +// Warning 6328: (A.sol:49-62): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/simple_imported_fail_two_pragmas.sol b/test/libsolidity/smtCheckerTests/imports/simple_imported_fail_two_pragmas.sol new file mode 100644 index 000000000..d0ba1b2f9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/simple_imported_fail_two_pragmas.sol @@ -0,0 +1,14 @@ +==== Source: ==== +import "A.sol"; +pragma experimental SMTChecker; +contract C is A {} +==== Source: A.sol ==== +pragma experimental SMTChecker; +contract A { + function f(uint x) public pure { + assert(x > 0); + } +} +// ---- +// Warning 6328: (A.sol:81-94): CHC: Assertion violation happens here. +// Warning 6328: (A.sol:81-94): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol index 92e53f40c..92606cbca 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol @@ -25,5 +25,5 @@ contract A is B { } } // ---- -// Warning 4984: (247-252): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (328-342): Assertion violation happens here +// Warning 4984: (247-252): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (328-342): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init.sol index 2cb40b5e9..7a3a186b4 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6328: (97-111): Assertion violation happens here +// Warning 6328: (97-111): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_base.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_base.sol index 26e2df7b1..bcb0f5562 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_base.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_base.sol @@ -11,4 +11,4 @@ contract D is C { } } // ---- -// Warning 6328: (117-131): Assertion violation happens here +// Warning 6328: (117-131): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain.sol index 2c43fb29d..0fa18859a 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain.sol @@ -19,4 +19,4 @@ contract D is C { } } // ---- -// Warning 6328: (211-225): Assertion violation happens here +// Warning 6328: (211-225): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_alternate.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_alternate.sol index fd04c33e9..f502ca8a8 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_alternate.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_alternate.sol @@ -18,4 +18,4 @@ contract D is C { } } // ---- -// Warning 6328: (185-199): Assertion violation happens here +// Warning 6328: (185-199): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol index 5538b9ee8..4a4e49517 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol @@ -22,10 +22,10 @@ contract A is B { } // ---- -// Warning 4984: (157-162): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (216-221): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (239-244): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (261-266): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (261-270): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (287-292): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (275-293): Assertion violation happens here +// Warning 4984: (157-162): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (216-221): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (239-244): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (261-266): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (261-270): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (287-292): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (275-293): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol index f597d60e4..f1768f693 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol @@ -22,9 +22,9 @@ contract A is B { } // ---- -// Warning 4984: (157-163): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (217-222): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (240-245): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (262-268): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4984: (285-290): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (273-291): Assertion violation happens here +// Warning 4984: (157-163): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (217-222): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (240-245): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (262-268): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (285-290): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (273-291): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond.sol index 49f22bad7..7d9092e44 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond.sol @@ -17,4 +17,4 @@ contract D is B, C { } } // ---- -// Warning 6328: (162-176): Assertion violation happens here +// Warning 6328: (162-176): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond_middle.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond_middle.sol index 8b54f27be..08690b634 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond_middle.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_diamond_middle.sol @@ -19,4 +19,4 @@ contract D is B, C { } } // ---- -// Warning 6328: (214-228): Assertion violation happens here +// Warning 6328: (214-228): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/fallback.sol b/test/libsolidity/smtCheckerTests/inheritance/fallback.sol index 1513f622f..917ed823b 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/fallback.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/fallback.sol @@ -21,6 +21,6 @@ contract B is A { } } // ---- -// Warning 6328: (122-136): Assertion violation happens here -// Warning 6328: (171-185): Assertion violation happens here -// Warning 6328: (288-302): Assertion violation happens here +// Warning 6328: (122-136): CHC: Assertion violation happens here. +// Warning 6328: (171-185): CHC: Assertion violation happens here. +// Warning 6328: (288-302): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/fallback_receive.sol b/test/libsolidity/smtCheckerTests/inheritance/fallback_receive.sol index 0fecccfb2..47ce43860 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/fallback_receive.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/fallback_receive.sol @@ -21,6 +21,6 @@ contract B is A { } } // ---- -// Warning 6328: (114-128): Assertion violation happens here -// Warning 6328: (163-177): Assertion violation happens here -// Warning 6328: (289-303): Assertion violation happens here +// Warning 6328: (114-128): CHC: Assertion violation happens here. +// Warning 6328: (163-177): CHC: Assertion violation happens here. +// Warning 6328: (289-303): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/functions_1.sol b/test/libsolidity/smtCheckerTests/inheritance/functions_1.sol index d8af4f292..38fa1f8be 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/functions_1.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/functions_1.sol @@ -19,6 +19,6 @@ contract B is A { } } // ---- -// Warning 6328: (121-135): Assertion violation happens here -// Warning 6328: (170-184): Assertion violation happens here -// Warning 6328: (276-290): Assertion violation happens here +// Warning 6328: (121-135): CHC: Assertion violation happens here. +// Warning 6328: (170-184): CHC: Assertion violation happens here. +// Warning 6328: (276-290): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/functions_2.sol b/test/libsolidity/smtCheckerTests/inheritance/functions_2.sol index e4b7d34b5..4b927e2d0 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/functions_2.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/functions_2.sol @@ -21,6 +21,6 @@ contract B is A { } } // ---- -// Warning 6328: (121-135): Assertion violation happens here -// Warning 6328: (170-184): Assertion violation happens here -// Warning 6328: (286-300): Assertion violation happens here +// Warning 6328: (121-135): CHC: Assertion violation happens here. +// Warning 6328: (170-184): CHC: Assertion violation happens here. +// Warning 6328: (286-300): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/functions_3.sol b/test/libsolidity/smtCheckerTests/inheritance/functions_3.sol index 6e8a4c2af..89701d2dd 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/functions_3.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/functions_3.sol @@ -36,9 +36,9 @@ contract C is B { } } // ---- -// Warning 6328: (121-135): Assertion violation happens here -// Warning 6328: (170-184): Assertion violation happens here -// Warning 6328: (296-310): Assertion violation happens here -// Warning 6328: (345-359): Assertion violation happens here -// Warning 6328: (468-482): Assertion violation happens here -// Warning 6328: (517-531): Assertion violation happens here +// Warning 6328: (121-135): CHC: Assertion violation happens here. +// Warning 6328: (170-184): CHC: Assertion violation happens here. +// Warning 6328: (296-310): CHC: Assertion violation happens here. +// Warning 6328: (345-359): CHC: Assertion violation happens here. +// Warning 6328: (468-482): CHC: Assertion violation happens here. +// Warning 6328: (517-531): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/receive.sol b/test/libsolidity/smtCheckerTests/inheritance/receive.sol index 8a9051260..5f513e209 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/receive.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/receive.sol @@ -21,6 +21,6 @@ contract B is A { } } // ---- -// Warning 6328: (128-142): Assertion violation happens here -// Warning 6328: (177-191): Assertion violation happens here -// Warning 6328: (300-314): Assertion violation happens here +// Warning 6328: (128-142): CHC: Assertion violation happens here. +// Warning 6328: (177-191): CHC: Assertion violation happens here. +// Warning 6328: (300-314): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol b/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol index d66d9354b..a9ad1e30e 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol @@ -21,6 +21,6 @@ contract B is A { } } // ---- -// Warning 6328: (120-134): Assertion violation happens here -// Warning 6328: (169-183): Assertion violation happens here -// Warning 6328: (288-302): Assertion violation happens here +// Warning 6328: (120-134): CHC: Assertion violation happens here. +// Warning 6328: (169-183): CHC: Assertion violation happens here. +// Warning 6328: (288-302): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/invariants/aon_blog_post.sol b/test/libsolidity/smtCheckerTests/invariants/aon_blog_post.sol index 50644943d..98674eece 100644 --- a/test/libsolidity/smtCheckerTests/invariants/aon_blog_post.sol +++ b/test/libsolidity/smtCheckerTests/invariants/aon_blog_post.sol @@ -44,4 +44,4 @@ contract C { } } // ---- -// Warning 6328: (689-699): Assertion violation happens here +// Warning 6328: (689-699): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol b/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol index 6303158f7..a1282c8cb 100644 --- a/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol +++ b/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol @@ -1,8 +1,5 @@ pragma experimental SMTChecker; -// This test gets different results on Linux and OSX. -// Re-enable when fixed (SMTSolvers: z3) - contract Simple { function f() public pure { uint x = 10; @@ -18,8 +15,4 @@ contract Simple { assert(y == x); } } -// ==== -// SMTSolvers: none // ---- -// Warning: (195-209): Error trying to invoke SMT solver. -// Warning: (195-209): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/invariants/state_machine_1_fail.sol b/test/libsolidity/smtCheckerTests/invariants/state_machine_1_fail.sol index 65a9ec407..a8e5339a7 100644 --- a/test/libsolidity/smtCheckerTests/invariants/state_machine_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/invariants/state_machine_1_fail.sol @@ -31,4 +31,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (311-324): Assertion violation happens here +// Warning 6328: (311-324): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/do_while_1_fail.sol b/test/libsolidity/smtCheckerTests/loops/do_while_1_fail.sol index c6cbafaef..c21f09127 100644 --- a/test/libsolidity/smtCheckerTests/loops/do_while_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/do_while_1_fail.sol @@ -13,4 +13,4 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (143-157): Assertion violation happens here +// Warning 6328: (143-157): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/do_while_break_2_fail.sol b/test/libsolidity/smtCheckerTests/loops/do_while_break_2_fail.sol index dd57c91c5..973a157ac 100644 --- a/test/libsolidity/smtCheckerTests/loops/do_while_break_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/do_while_break_2_fail.sol @@ -19,4 +19,4 @@ contract C { // ---- // Warning 5740: (128-133): Unreachable code. // Warning 5740: (147-151): Unreachable code. -// Warning 6328: (180-194): Assertion violation happens here +// Warning 6328: (180-194): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/do_while_break_fail.sol b/test/libsolidity/smtCheckerTests/loops/do_while_break_fail.sol index e1c170606..c86805b26 100644 --- a/test/libsolidity/smtCheckerTests/loops/do_while_break_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/do_while_break_fail.sol @@ -15,4 +15,4 @@ contract C { // ---- // Warning 5740: (104-109): Unreachable code. // Warning 5740: (122-128): Unreachable code. -// Warning 6328: (133-147): Assertion violation happens here +// Warning 6328: (133-147): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_break_fail.sol b/test/libsolidity/smtCheckerTests/loops/for_1_break_fail.sol index 77c1800c2..319bd1de6 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_break_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_break_fail.sol @@ -17,4 +17,4 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (201-216): Assertion violation happens here +// Warning 6328: (201-216): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol b/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol index bb5ec1ae3..12afb84e1 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol @@ -14,4 +14,4 @@ contract C // SMTSolvers: z3 // ---- // Warning 5667: (66-72): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning 6328: (142-156): Assertion violation happens here +// Warning 6328: (142-156): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_fail.sol b/test/libsolidity/smtCheckerTests/loops/for_1_fail.sol index 0579325df..c05da9572 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_fail.sol @@ -14,6 +14,5 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 1218: (176-181): Error trying to invoke SMT solver. -// Warning 6328: (189-203): Assertion violation happens here -// Warning 2661: (176-181): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 6328: (189-203): CHC: Assertion violation happens here. +// Warning 2661: (176-181): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol index ff3d584e6..f4176588e 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol @@ -13,8 +13,5 @@ contract C assert(x > 0); } } -// ==== -// SMTSolvers: cvc4 // ---- -// Warning 2661: (176-181): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 4661: (296-309): Assertion violation happens here +// Warning 2661: (176-181): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol index f9cf1c50f..67402e3cd 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (136-150): Assertion violation happens here +// Warning 6328: (136-150): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol index 26a9f0407..7af2112df 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol @@ -11,4 +11,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (167-181): Assertion violation happens here +// Warning 6328: (167-181): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol index 1228e6d3d..e8268e1f4 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol @@ -15,6 +15,6 @@ contract LoopFor2 { } } // ---- -// Warning 6328: (281-301): Assertion violation happens here -// Warning 6328: (305-324): Assertion violation happens here -// Warning 6328: (328-347): Assertion violation happens here +// Warning 6328: (281-301): CHC: Assertion violation happens here. +// Warning 6328: (305-324): CHC: Assertion violation happens here. +// Warning 6328: (328-347): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol index 76cfa0569..e625e67c0 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol @@ -19,5 +19,5 @@ contract LoopFor2 { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (274-294): Assertion violation happens here -// Warning 6328: (321-340): Assertion violation happens here +// Warning 6328: (274-294): CHC: Assertion violation happens here. +// Warning 6328: (321-340): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol index 7f859ef82..b3581fbc0 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol @@ -19,4 +19,4 @@ contract LoopFor2 { } } // ---- -// Warning 6328: (363-382): Assertion violation happens here +// Warning 6328: (363-382): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol index b8cf6aef4..88bb839c1 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol @@ -19,5 +19,5 @@ contract LoopFor2 { } } // ---- -// Warning 6328: (341-360): Assertion violation happens here -// Warning 6328: (364-383): Assertion violation happens here +// Warning 6328: (341-360): CHC: Assertion violation happens here. +// Warning 6328: (364-383): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_1.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_1.sol index 2f74a8993..c8457bc85 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_1.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_1.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6838: (122-128): Condition is always true. +// Warning 6838: (122-128): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_2.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_2.sol index ccf65cb29..087e40a84 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_2.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_trivial_condition_2.sol @@ -12,4 +12,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6838: (138-144): Condition is always true. +// Warning 6838: (138-144): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_unreachable_1.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_unreachable_1.sol index 632d7ecac..3c3f29ab1 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_unreachable_1.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_unreachable_1.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6838: (122-127): Condition is always false. +// Warning 6838: (122-127): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/loops/while_1_break_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_1_break_fail.sol index aafab6942..6d58a4cf1 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_1_break_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_1_break_fail.sol @@ -18,4 +18,4 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (218-233): Assertion violation happens here +// Warning 6328: (218-233): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_1_continue_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_1_continue_fail.sol index 7bb08f68f..f0500c073 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_1_continue_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_1_continue_fail.sol @@ -21,4 +21,4 @@ contract C // SMTSolvers: z3 // ---- // Warning 5740: (169-176): Unreachable code. -// Warning 6328: (227-242): Assertion violation happens here +// Warning 6328: (227-242): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_1_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_1_fail.sol index d5d3f78ac..2b131133e 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_1_fail.sol @@ -13,4 +13,4 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (139-153): Assertion violation happens here +// Warning 6328: (139-153): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_2_break_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_2_break_fail.sol index f203f38cb..2ffb7e023 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_2_break_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_2_break_fail.sol @@ -15,4 +15,4 @@ contract C // SMTSolvers: z3 // ---- // Warning 5740: (120-123): Unreachable code. -// Warning 6328: (131-145): Assertion violation happens here +// Warning 6328: (131-145): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_break_direct.sol b/test/libsolidity/smtCheckerTests/loops/while_break_direct.sol index 58d4c6f0a..ab94d5414 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_break_direct.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_break_direct.sol @@ -12,4 +12,4 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 6838: (98-104): Condition is always true. +// Warning 6838: (98-104): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_memory.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_memory.sol index d10ba5b42..53dab3af3 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_memory.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_memory.sol @@ -19,7 +19,6 @@ contract LoopFor2 { // ==== // SMTSolvers: z3 // ---- -// Warning 1218: (244-249): Error trying to invoke SMT solver. -// Warning 6328: (281-301): Assertion violation happens here -// Warning 6328: (305-324): Assertion violation happens here -// Warning 6328: (328-347): Assertion violation happens here +// Warning 6328: (281-301): CHC: Assertion violation happens here. +// Warning 6328: (305-324): CHC: Assertion violation happens here. +// Warning 6328: (328-347): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_storage.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_storage.sol index b61baaac9..23a20c01f 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_memory_storage.sol @@ -23,6 +23,5 @@ contract LoopFor2 { // ==== // SMTSolvers: z3 // ---- -// Warning 1218: (237-242): Error trying to invoke SMT solver. -// Warning 6328: (362-382): Assertion violation happens here -// Warning 6328: (409-428): Assertion violation happens here +// Warning 6328: (362-382): CHC: Assertion violation happens here. +// Warning 6328: (409-428): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol index c26a19a1a..386af5fca 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol @@ -20,9 +20,7 @@ contract LoopFor2 { assert(b[0] == 900); } } -// ==== -// SMTSolvers: cvc4 // ---- -// Warning 4661: (296-316): Assertion violation happens here -// Warning 4661: (320-339): Assertion violation happens here -// Warning 4661: (343-362): Assertion violation happens here +// Warning 6328: (320-339): CHC: Assertion violation happens here. +// Warning 6328: (343-362): CHC: Assertion violation happens here. +// Warning 4661: (296-316): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol index 026de2441..ef47d5b81 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol @@ -12,4 +12,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (194-208): Assertion violation happens here +// Warning 6328: (194-208): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol index 7e11d2be1..0d6b2ad6f 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol @@ -10,4 +10,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (187-201): Assertion violation happens here +// Warning 6328: (187-201): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol index f2b8238eb..d357d5d05 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol @@ -12,4 +12,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (224-238): Assertion violation happens here +// Warning 6328: (224-238): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol index 4b2186d13..00fe1ffee 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol @@ -29,5 +29,5 @@ contract C } } // ---- -// Warning 6328: (329-344): Assertion violation happens here -// Warning 6328: (380-395): Assertion violation happens here +// Warning 6328: (329-344): CHC: Assertion violation happens here. +// Warning 6328: (380-395): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol index 4e5faf906..fe7384fff 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol @@ -27,5 +27,5 @@ contract C } } // ---- -// Warning 6328: (323-338): Assertion violation happens here -// Warning 6328: (362-377): Assertion violation happens here +// Warning 6328: (323-338): CHC: Assertion violation happens here. +// Warning 6328: (362-377): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol index 6f3701d41..d87b82129 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol @@ -21,5 +21,5 @@ contract C } } // ---- -// Warning 4984: (203-208): Overflow (resulting value larger than 2**256 - 1) happens here. -// Warning 6328: (136-149): Assertion violation happens here +// Warning 4984: (203-208): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (136-149): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_control_flow.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_control_flow.sol index 503d276e3..aa189243c 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_control_flow.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_control_flow.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6328: (144-157): Assertion violation happens here +// Warning 6328: (144-157): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_inline_function_inside_branch.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_inline_function_inside_branch.sol index bb46594fe..11df23d93 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_inline_function_inside_branch.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_inline_function_inside_branch.sol @@ -17,5 +17,3 @@ contract C } } // ---- -// Warning 5084: (205-215): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (205-215): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol index 13679bfa4..52563ad89 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol @@ -20,4 +20,4 @@ contract C { } } // ---- -// Warning 6328: (287-300): Assertion violation happens here +// Warning 6328: (287-300): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_branch.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_branch.sol index 82a2c67e9..6c9489482 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_branch.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_branch.sol @@ -24,4 +24,4 @@ contract C { } } // ---- -// Warning 6838: (266-271): Condition is always true. +// Warning 6838: (266-271): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol index d1ef8639e..f5134efc7 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol @@ -34,5 +34,5 @@ contract C { } } // ---- -// Warning 6328: (516-534): Assertion violation happens here -// Warning 6328: (573-587): Assertion violation happens here +// Warning 6328: (516-534): CHC: Assertion violation happens here. +// Warning 6328: (573-587): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi.sol index 49fcac03b..35a76250f 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi.sol @@ -26,4 +26,4 @@ contract C } } // ---- -// Warning 6328: (170-183): Assertion violation happens here +// Warning 6328: (170-183): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions.sol index 185dd7ef7..dc6fa718b 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions.sol @@ -22,4 +22,4 @@ contract C } } // ---- -// Warning 6328: (311-324): Assertion violation happens here +// Warning 6328: (311-324): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_parameters.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_parameters.sol index 7f9c544b4..56754da76 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_parameters.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_parameters.sol @@ -13,4 +13,4 @@ contract C } } // ---- -// Warning 6328: (164-177): Assertion violation happens here +// Warning 6328: (164-177): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_parameter_copy.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_parameter_copy.sol index bbf21a290..a90a8d21c 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_parameter_copy.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_parameter_copy.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (128-142): Assertion violation happens here +// Warning 6328: (128-142): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_same_local_variables.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_same_local_variables.sol index ce69706f0..d70cfd9d3 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_same_local_variables.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_same_local_variables.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (121-135): Assertion violation happens here +// Warning 6328: (121-135): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_two_placeholders.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_two_placeholders.sol index 3e2a645fc..11385044e 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_two_placeholders.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_two_placeholders.sol @@ -23,4 +23,4 @@ contract C } } // ---- -// Warning 6328: (156-170): Assertion violation happens here +// Warning 6328: (156-170): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_and_int.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_and_int.sol index 51bd01e5c..644235029 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_and_int.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_and_int.sol @@ -15,4 +15,4 @@ contract C { } } // ---- -// Warning 6328: (104-122): Assertion violation happens here +// Warning 6328: (104-122): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_and_rational.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_and_rational.sol index 79e63a8d7..f959290c5 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_and_rational.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_and_rational.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (76-94): Assertion violation happens here +// Warning 6328: (76-94): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_and_uint.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_and_uint.sol index dbb3ab473..8e11c17dc 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_and_uint.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_and_uint.sol @@ -13,6 +13,6 @@ contract C { } } // ---- -// Warning 6328: (107-125): Assertion violation happens here -// Warning 6328: (180-203): Assertion violation happens here -// Warning 6328: (207-230): Assertion violation happens here +// Warning 6328: (107-125): CHC: Assertion violation happens here. +// Warning 6328: (180-203): CHC: Assertion violation happens here. +// Warning 6328: (207-230): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_not_int.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_not_int.sol index d879f8ee7..7578b8ac3 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_not_int.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_not_int.sol @@ -15,7 +15,7 @@ contract C { } } // ---- -// Warning 6328: (91-106): Assertion violation happens here -// Warning 6328: (122-137): Assertion violation happens here -// Warning 6328: (153-171): Assertion violation happens here -// Warning 6328: (185-200): Assertion violation happens here +// Warning 6328: (91-106): CHC: Assertion violation happens here. +// Warning 6328: (122-137): CHC: Assertion violation happens here. +// Warning 6328: (153-171): CHC: Assertion violation happens here. +// Warning 6328: (185-200): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_not_uint.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_not_uint.sol index 8b733de18..494348d28 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_not_uint.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_not_uint.sol @@ -11,5 +11,5 @@ contract C { } } // ---- -// Warning 6328: (159-179): Assertion violation happens here -// Warning 6328: (183-203): Assertion violation happens here +// Warning 6328: (159-179): CHC: Assertion violation happens here. +// Warning 6328: (183-203): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_or_int.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_or_int.sol index 140c255c6..fb7a14614 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_or_int.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_or_int.sol @@ -17,5 +17,5 @@ contract C { } } // ---- -// Warning 6328: (144-162): Assertion violation happens here -// Warning 6328: (267-286): Assertion violation happens here +// Warning 6328: (144-162): CHC: Assertion violation happens here. +// Warning 6328: (267-286): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_or_uint.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_or_uint.sol index f93c59a69..bba881d19 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_or_uint.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_or_uint.sol @@ -13,5 +13,5 @@ contract C { } } // ---- -// Warning 6328: (155-176): Assertion violation happens here -// Warning 6328: (207-230): Assertion violation happens here +// Warning 6328: (155-176): CHC: Assertion violation happens here. +// Warning 6328: (207-230): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_rational_1.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_rational_1.sol index 97343e235..32928e350 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_rational_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_rational_1.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (169-192): Assertion violation happens here +// Warning 6328: (169-192): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_rational_2.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_rational_2.sol index 94bb5cc83..01707c852 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_rational_2.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_rational_2.sol @@ -12,4 +12,4 @@ contract C { } } // ---- -// Warning 6328: (181-194): Assertion violation happens here +// Warning 6328: (181-194): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_xor_int.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_xor_int.sol index 87bdd7f8d..96383eabe 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_xor_int.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_xor_int.sol @@ -15,5 +15,5 @@ contract C { } } // ---- -// Warning 6328: (189-206): Assertion violation happens here -// Warning 6328: (247-264): Assertion violation happens here +// Warning 6328: (189-206): CHC: Assertion violation happens here. +// Warning 6328: (247-264): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_xor_uint.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_xor_uint.sol index 70ae0eac6..5a2837f7c 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_xor_uint.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_xor_uint.sol @@ -13,5 +13,5 @@ contract C { } } // ---- -// Warning 6328: (155-176): Assertion violation happens here -// Warning 6328: (207-230): Assertion violation happens here +// Warning 6328: (155-176): CHC: Assertion violation happens here. +// Warning 6328: (207-230): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/bytes_new.sol b/test/libsolidity/smtCheckerTests/operators/bytes_new.sol new file mode 100644 index 000000000..968a0935b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/bytes_new.sol @@ -0,0 +1,36 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + bytes memory x = new bytes(0); + assert(x.length == 0); + } + function g() public pure { + bytes memory x = new bytes(3); + assert(x.length == 3); + assert(x[0] == 0); + assert(x[1] == 0); + assert(x[2] == 0); + } + function h() public pure { + bytes memory x = new bytes(3); + assert(x.length == 3); + x[0] = 0x12; + x[1] = 0x34; + assert(x[0] == 0x12); + assert(x[1] == 0x34); + // This should be an out-of-bounds assertion. + x[5] = 0xff; + assert(x[5] == 0xff); + } + function h(uint size) public pure { + bytes memory x = new bytes(size); + assert(x.length == size); + require(size >= 2); + x[0] = 0x12; + x[1] = 0x34; + assert(x[0] == 0x12); + assert(x[1] == 0x34); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/compound_add.sol b/test/libsolidity/smtCheckerTests/operators/compound_add.sol index 43219d9c3..fc2383e53 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_add.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_add.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (151-166): Assertion violation happens here +// Warning 6328: (151-166): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol b/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol index 5c989e31e..cb7132148 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (192-214): Assertion violation happens here +// Warning 6328: (192-214): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_add_mapping.sol b/test/libsolidity/smtCheckerTests/operators/compound_add_mapping.sol index bf48a540a..e53c80ab5 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_add_mapping.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_add_mapping.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (198-218): Assertion violation happens here +// Warning 6328: (198-218): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_1.sol index b19d038d3..d5b3b7176 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_1.sol @@ -9,6 +9,6 @@ contract C { } } // ---- -// Warning 1218: (129-143): Error trying to invoke SMT solver. -// Warning 1218: (147-161): Error trying to invoke SMT solver. -// Warning 4661: (147-161): Assertion violation happens here +// Warning 1218: (129-143): CHC: Error trying to invoke SMT solver. +// Warning 1218: (147-161): CHC: Error trying to invoke SMT solver. +// Warning 4661: (147-161): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_2.sol b/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_2.sol index 427703366..87e0ba152 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_2.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_2.sol @@ -10,6 +10,6 @@ contract C { } } // ---- -// Warning 1218: (163-184): Error trying to invoke SMT solver. -// Warning 1218: (188-209): Error trying to invoke SMT solver. -// Warning 4661: (188-209): Assertion violation happens here +// Warning 1218: (163-184): CHC: Error trying to invoke SMT solver. +// Warning 1218: (188-209): CHC: Error trying to invoke SMT solver. +// Warning 4661: (188-209): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_3.sol b/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_3.sol index da3b81254..cffb2b5a1 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_3.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_assignment_division_3.sol @@ -10,6 +10,6 @@ contract C { } } // ---- -// Warning 1218: (171-190): Error trying to invoke SMT solver. -// Warning 1218: (194-213): Error trying to invoke SMT solver. -// Warning 4661: (194-213): Assertion violation happens here +// Warning 1218: (171-190): CHC: Error trying to invoke SMT solver. +// Warning 1218: (194-213): CHC: Error trying to invoke SMT solver. +// Warning 4661: (194-213): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_1.sol deleted file mode 100644 index 8ca1152e3..000000000 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_1.sol +++ /dev/null @@ -1,13 +0,0 @@ -pragma experimental SMTChecker; - -contract C { - function f(bool b) public pure { - uint v = 1; - if (b) - v &= 1; - assert(v == 1); - } -} -// ---- -// Warning 6328: (116-130): Assertion violation happens here -// Warning 9149: (106-112): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol new file mode 100644 index 000000000..b1db36acd --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; +contract C { + function f() public pure returns (byte) { + byte a = 0xff; + byte b = 0xf0; + a &= b; + assert(a == b); + + a &= ~b; + assert(a != 0); // fails + } +} +// ---- +// Warning 6328: (203-217): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_int.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_int.sol new file mode 100644 index 000000000..a46e71bc9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_int.sol @@ -0,0 +1,21 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + int8 x = 1; + int8 y = 0; + x &= y; + assert(x != 0); // fails + x = -1; y = 3; + y &= x; + assert(y == 3); + y = -1; + y &= x; + assert(y == -1); + y = 127; + x &= y; + assert(x == 127); + } +} +// ---- +// Warning 6328: (114-128): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_uint.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_uint.sol new file mode 100644 index 000000000..30897aac7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_uint.sol @@ -0,0 +1,33 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + uint v = 1; + v &= 1; + assert(v == 1); + + v = 7; + v &= 3; + assert(v != 3); // fails, as 7 & 3 = 3 + + uint c = 0; + c &= v; + assert(c == 0); + + uint8 x = 0xff; + uint16 y = 0xffff; + y &= x; + assert(y == 0xff); + assert(y == 0xffff); // fails + + y = 0xffff; + x = 0xff; + y &= y | x; + assert(y == 0xffff); + assert(y == 0xff); // fails + } +} +// ---- +// Warning 6328: (177-191): CHC: Assertion violation happens here. +// Warning 6328: (380-399): CHC: Assertion violation happens here. +// Warning 6328: (506-523): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_1.sol deleted file mode 100644 index 24e61cf58..000000000 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_1.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma experimental SMTChecker; -contract C { - int[1] c; - function f(bool b) public { - if (b) - c[0] |= 1; - } -} -// ---- -// Warning 9149: (97-106): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_2.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_2.sol deleted file mode 100644 index 4569afa88..000000000 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_2.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma experimental SMTChecker; -contract C { - int[1][20] c; - function f(bool b) public { - if (b) - c[10][0] |= 1; - } -} -// ---- -// Warning 9149: (101-114): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_3.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_3.sol deleted file mode 100644 index 617ae7af3..000000000 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_3.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma experimental SMTChecker; -contract C { - struct S { - uint x; - } - S s; - function f(bool b) public { - if (b) - s.x |= 1; - } -} -// ---- -// Warning 8115: (71-74): Assertion checker does not yet support the type of this variable. -// Warning 7650: (117-120): Assertion checker does not yet support this expression. -// Warning 8364: (117-118): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9149: (117-125): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_4.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_4.sol deleted file mode 100644 index 091f0ca0d..000000000 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_4.sol +++ /dev/null @@ -1,17 +0,0 @@ -pragma experimental SMTChecker; -contract C { - struct S { - uint[] x; - } - S s; - function f(bool b) public { - if (b) - s.x[2] |= 1; - } -} -// ---- -// Warning 8115: (73-76): Assertion checker does not yet support the type of this variable. -// Warning 7650: (119-122): Assertion checker does not yet support this expression. -// Warning 8364: (119-120): Assertion checker does not yet implement type struct C.S storage ref -// Warning 9118: (119-125): Assertion checker does not yet implement this expression. -// Warning 9149: (119-130): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol new file mode 100644 index 000000000..613ac8952 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; +contract C { + function f() public pure returns (byte) { + byte a = 0xff; + byte b = 0xf0; + b |= a; + assert(a == b); + + a |= ~b; + assert(a == 0); // fails + } +} +// ---- +// Warning 6328: (203-217): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_int.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_int.sol new file mode 100644 index 000000000..125d4233b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_int.sol @@ -0,0 +1,21 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + int8 x = 1; + int8 y = 0; + x |= y; + assert(x == 0); // fails + x = -1; y = 3; + x |= y; + assert(x == -1); + x = 4; + y |= x; + assert(y == 7); + y = 127; + x |= y; + assert(x == 127); + } +} +// ---- +// Warning 6328: (114-128): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_int_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_int_1.sol new file mode 100644 index 000000000..e25ae354d --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_int_1.sol @@ -0,0 +1,11 @@ +pragma experimental SMTChecker; +contract C { + int[1][20] c; + function f(bool b) public { + require(c[10][0] == 0); + if (b) + c[10][0] |= 1; + assert(c[10][0] == 0 || c[10][0] == 1); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint.sol new file mode 100644 index 000000000..c4d124076 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + uint v = 7; + v |= 3; + assert(v != 7); // fails, as 7 | 3 = 7 + + uint c = 0; + c |= v; + assert(c == 7); + + uint16 x = 0xff; + uint16 y = 0xffff; + y |= x; + assert(y == 0xff); // fails + assert(y == 0xffff); + + y = 0xf1ff; + x = 0xff00; + x |= y & x; + assert(y == 0xffff); // fails + assert(x == 0xff00); + } +} +// ---- +// Warning 6328: (121-135): CHC: Assertion violation happens here. +// Warning 6328: (298-315): CHC: Assertion violation happens here. +// Warning 6328: (424-443): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_1.sol new file mode 100644 index 000000000..790d30a76 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_1.sol @@ -0,0 +1,11 @@ +pragma experimental SMTChecker; +contract C { + uint[1] c; + function f(bool b) public { + require(c[0] == 0); + if (b) + c[0] |= 1; + assert(c[0] <= 1); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_2.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_2.sol new file mode 100644 index 000000000..714c0df22 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_2.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; +contract C { + struct S { + uint[] x; + } + S s; + function f(bool b) public { + if (b) + s.x[2] |= 1; + assert(s.x[2] != 1); + } +} +// ---- +// Warning 7812: (173-192): BMC: Assertion violation might happen here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_3.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_3.sol new file mode 100644 index 000000000..46311b750 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_uint_3.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; +contract C { + struct S { + uint x; + } + S s; + function f(bool b) public { + s.x |= b ? 1 : 2; + assert(s.x > 0); + } +} +// ---- +// Warning 7812: (157-172): BMC: Assertion violation might happen here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_1.sol deleted file mode 100644 index 2e07a32f7..000000000 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_1.sol +++ /dev/null @@ -1,13 +0,0 @@ -pragma experimental SMTChecker; - -contract C { - function f(bool b) public pure { - uint v = 0; - if (b) - v ^= 1; - assert(v == 1); - } -} -// ---- -// Warning 6328: (116-130): Assertion violation happens here -// Warning 9149: (106-112): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol new file mode 100644 index 000000000..f1d57b68e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; +contract C { + function f() public pure returns (byte) { + byte a = 0xff; + byte b = 0xf0; + a ^= ~b; + assert(a == b); + + a ^= ~b; + assert(a != 0xff); // fails + } +} +// ---- +// Warning 6328: (204-221): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_int.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_int.sol new file mode 100644 index 000000000..179c5bf85 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_int.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + int8 x = 1; + int8 y = 0; + x ^= y; + assert(x != 1); // fails + x = -1; y = 1; + x ^= y; + assert(x == -2); + x = 4; + y ^= x; + assert(y == 5); + } +} +// ---- +// Warning 6328: (114-128): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_uint.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_uint.sol new file mode 100644 index 000000000..0988fac42 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_uint.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + uint v = 7; + v ^= 3; + assert(v != 4); // fails, as 7 ^ 3 = 4 + + uint c = 0; + c ^= v; + assert(c == 4); + + uint16 x = 0xff; + uint16 y = 0xffff; + y ^= x; + assert(y == 0xff); // fails + assert(y == 0xff00); + + y = 0xf1; + x = 0xff00; + y ^= x | y; + assert(y == 0xffff); // fails + assert(x == 0xff00); + } +} +// ---- +// Warning 6328: (121-135): CHC: Assertion violation happens here. +// Warning 6328: (298-315): CHC: Assertion violation happens here. +// Warning 6328: (422-441): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_mul.sol b/test/libsolidity/smtCheckerTests/operators/compound_mul.sol index 6723e5304..900a237bc 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_mul.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_mul.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (150-164): Assertion violation happens here +// Warning 6328: (150-164): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_mul_array_index.sol b/test/libsolidity/smtCheckerTests/operators/compound_mul_array_index.sol index 663f0702b..4dd85d7f9 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_mul_array_index.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_mul_array_index.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (191-212): Assertion violation happens here +// Warning 6328: (191-212): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_mul_mapping.sol b/test/libsolidity/smtCheckerTests/operators/compound_mul_mapping.sol index cdfc7500a..3495fe534 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_mul_mapping.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_mul_mapping.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (197-216): Assertion violation happens here +// Warning 6328: (197-216): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_shl_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_shl_1.sol index 964c02b46..8ccc8a800 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_shl_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_shl_1.sol @@ -9,5 +9,3 @@ contract C { } } // ---- -// Warning 6328: (123-136): Assertion violation happens here -// Warning 9149: (112-119): Assertion checker does not yet implement this assignment operator. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_shr_1.sol b/test/libsolidity/smtCheckerTests/operators/compound_shr_1.sol index a42a1e3e6..a2a7ca5ab 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_shr_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_shr_1.sol @@ -9,5 +9,4 @@ contract C { } } // ---- -// Warning 6328: (117-130): Assertion violation happens here -// Warning 9149: (106-113): Assertion checker does not yet implement this assignment operator. +// Warning 6328: (117-130): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_sub.sol b/test/libsolidity/smtCheckerTests/operators/compound_sub.sol index 609dedd69..c4929220e 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_sub.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_sub.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (150-164): Assertion violation happens here +// Warning 6328: (150-164): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_sub_array_index.sol b/test/libsolidity/smtCheckerTests/operators/compound_sub_array_index.sol index 39ebd357b..169bb5dd5 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_sub_array_index.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_sub_array_index.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (191-212): Assertion violation happens here +// Warning 6328: (191-212): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/compound_sub_mapping.sol b/test/libsolidity/smtCheckerTests/operators/compound_sub_mapping.sol index 883105dd5..4215fdd12 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_sub_mapping.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_sub_mapping.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (197-216): Assertion violation happens here +// Warning 6328: (197-216): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_1.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_1.sol index f01fb6029..65ad1920a 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_1.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 6328: (104-117): Assertion violation happens here +// Warning 6328: (104-117): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_2.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_2.sol index 99ee3c2a0..3dfd6271f 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_2.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_2.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6328: (132-146): Assertion violation happens here +// Warning 6328: (132-146): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_3.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_3.sol index 12c580e24..d4707c217 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_3.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_3.sol @@ -10,4 +10,4 @@ contract C { } } // ---- -// Warning 6328: (161-174): Assertion violation happens here +// Warning 6328: (161-174): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_5.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_5.sol index 675ae3eb5..710d89416 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_5.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_5.sol @@ -24,4 +24,4 @@ contract C { } // ---- // Warning 2072: (288-294): Unused local variable. -// Warning 6328: (318-342): Assertion violation happens here +// Warning 6328: (318-342): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_false.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_false.sol index 7958e0237..3f3eff797 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_false.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_false.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6838: (148-153): Condition is always false. +// Warning 6838: (148-153): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_true.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_true.sol index 705ca9c2b..0a6995732 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_true.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_always_true.sol @@ -8,5 +8,5 @@ contract C { } } // ---- -// Warning 6328: (118-131): Assertion violation happens here -// Warning 6838: (105-106): Condition is always true. +// Warning 6328: (118-131): CHC: Assertion violation happens here. +// Warning 6838: (105-106): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_1.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_1.sol index 890db61ca..1f1557058 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_1.sol @@ -10,4 +10,4 @@ contract C { } } // ---- -// Warning 6328: (203-216): Assertion violation happens here +// Warning 6328: (203-216): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_2.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_2.sol index 47ec79ab5..e10de61e8 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_2.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_function_2.sol @@ -16,4 +16,4 @@ contract C { } } // ---- -// Warning 6328: (378-392): Assertion violation happens here +// Warning 6328: (378-392): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_always_true.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_always_true.sol index cd85df0c4..562631dec 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_always_true.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_always_true.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6838: (147-149): Condition is always true. +// Warning 6838: (147-149): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_unsafe.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_unsafe.sol index 0dabdf0f6..dd8a2bbbf 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_nested_unsafe.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 6328: (141-154): Assertion violation happens here +// Warning 6328: (141-154): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_array.sol b/test/libsolidity/smtCheckerTests/operators/delete_array.sol index 9c513e140..d56872995 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_array.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_array.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6838: (118-119): Condition is always true. +// Warning 6838: (118-119): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_array_index.sol b/test/libsolidity/smtCheckerTests/operators/delete_array_index.sol index 517fdf0ae..f3da3ea29 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_array_index.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_array_index.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6838: (119-120): Condition is always false. +// Warning 6838: (119-120): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol b/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol index 5627953eb..b79994cc3 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol @@ -17,4 +17,4 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning 6328: (191-211): Assertion violation happens here +// Warning 6328: (191-211): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_function.sol b/test/libsolidity/smtCheckerTests/operators/delete_function.sol index 64e397ae1..f7a981e50 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_function.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_function.sol @@ -21,4 +21,4 @@ contract C } } // ---- -// Warning 6838: (201-202): Condition is always true. +// Warning 6838: (201-202): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_multid_array.sol b/test/libsolidity/smtCheckerTests/operators/delete_multid_array.sol index f52da7a3d..9d3f9ba64 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_multid_array.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_multid_array.sol @@ -37,8 +37,6 @@ contract C { b[x][y] = z; } } -// ==== -// SMTSolvers: cvc4 // ---- -// Warning 4661: (372-392): Assertion violation happens here -// Warning 4661: (617-637): Assertion violation happens here +// Warning 6328: (372-392): CHC: Assertion violation happens here. +// Warning 6328: (617-637): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_struct.sol b/test/libsolidity/smtCheckerTests/operators/delete_struct.sol index 5b7be5add..01fa7558b 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_struct.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_struct.sol @@ -6,7 +6,7 @@ contract C { uint x; } - function f(bool b) public { + function f(bool b) public pure { S memory s; s.x = 2; if (b) @@ -17,15 +17,3 @@ contract C } } // ---- -// Warning 2018: (73-192): Function state mutability can be restricted to pure -// Warning 6328: (172-188): Assertion violation happens here -// Warning 8115: (103-113): Assertion checker does not yet support the type of this variable. -// Warning 7650: (117-120): Assertion checker does not yet support this expression. -// Warning 8364: (117-118): Assertion checker does not yet implement type struct C.S memory -// Warning 8182: (117-124): Assertion checker does not yet implement such assignments. -// Warning 8364: (145-146): Assertion checker does not yet implement type struct C.S memory -// Warning 7650: (165-168): Assertion checker does not yet support this expression. -// Warning 8364: (165-166): Assertion checker does not yet implement type struct C.S memory -// Warning 2683: (158-168): Assertion checker does not yet implement "delete" for this expression. -// Warning 7650: (179-182): Assertion checker does not yet support this expression. -// Warning 8364: (179-180): Assertion checker does not yet implement type struct C.S memory diff --git a/test/libsolidity/smtCheckerTests/operators/div_zero.sol b/test/libsolidity/smtCheckerTests/operators/div_zero.sol index 81f32822b..b11b82d0e 100644 --- a/test/libsolidity/smtCheckerTests/operators/div_zero.sol +++ b/test/libsolidity/smtCheckerTests/operators/div_zero.sol @@ -5,4 +5,4 @@ contract C { uint x = 2 / z; } // ---- -// Warning 6084: (69-74): Division by zero happens here. +// Warning 6084: (69-74): BMC: Division by zero happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/division_1.sol b/test/libsolidity/smtCheckerTests/operators/division_1.sol index 85e978905..99b36e480 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_1.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// Warning 3046: (111-116): Division by zero happens here +// Warning 3046: (111-116): BMC: Division by zero happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/division_3.sol b/test/libsolidity/smtCheckerTests/operators/division_3.sol index dd82c5bb7..522212855 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_3.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_3.sol @@ -6,5 +6,5 @@ contract C { } } // ---- -// Warning 1218: (127-132): Error trying to invoke SMT solver. -// Warning 2661: (127-132): Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here +// Warning 1218: (127-132): CHC: Error trying to invoke SMT solver. +// Warning 2661: (127-132): BMC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/division_4.sol b/test/libsolidity/smtCheckerTests/operators/division_4.sol index 52e3db08b..b9add545b 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_4.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_4.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 1218: (147-152): Error trying to invoke SMT solver. +// Warning 1218: (147-152): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_5.sol b/test/libsolidity/smtCheckerTests/operators/division_5.sol index 6458dd8e3..70c67d96c 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_5.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_5.sol @@ -10,4 +10,4 @@ contract C { } } // ---- -// Warning 1218: (151-156): Error trying to invoke SMT solver. +// Warning 1218: (151-156): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_6.sol b/test/libsolidity/smtCheckerTests/operators/division_6.sol index 7da33cbaa..198f9e800 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_6.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_6.sol @@ -12,4 +12,4 @@ contract C { } } // ---- -// Warning 1218: (265-270): Error trying to invoke SMT solver. +// Warning 1218: (265-270): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_1.sol b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_1.sol index cd1365997..331da0d47 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_1.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_1.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 1218: (107-125): Error trying to invoke SMT solver. +// Warning 1218: (107-125): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_2.sol b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_2.sol index a5a8daf59..21acea379 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_2.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_2.sol @@ -7,5 +7,5 @@ contract C { } } // ---- -// Warning 1218: (112-117): Error trying to invoke SMT solver. -// Warning 1218: (105-123): Error trying to invoke SMT solver. +// Warning 1218: (112-117): CHC: Error trying to invoke SMT solver. +// Warning 1218: (105-123): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_3.sol b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_3.sol index 8c903a242..354325e7c 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_3.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_3.sol @@ -7,5 +7,5 @@ contract C { } } // ---- -// Warning 1218: (113-118): Error trying to invoke SMT solver. -// Warning 1218: (106-125): Error trying to invoke SMT solver. +// Warning 1218: (113-118): CHC: Error trying to invoke SMT solver. +// Warning 1218: (106-125): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_4.sol b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_4.sol index 0514b894f..5024e6805 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_4.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_4.sol @@ -7,5 +7,5 @@ contract C { } } // ---- -// Warning 1218: (113-118): Error trying to invoke SMT solver. -// Warning 1218: (106-125): Error trying to invoke SMT solver. +// Warning 1218: (113-118): CHC: Error trying to invoke SMT solver. +// Warning 1218: (106-125): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_5.sol b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_5.sol index 348ad0dd5..e59d26295 100644 --- a/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_5.sol +++ b/test/libsolidity/smtCheckerTests/operators/division_truncates_correctly_5.sol @@ -7,5 +7,5 @@ contract C { } } // ---- -// Warning 1218: (114-119): Error trying to invoke SMT solver. -// Warning 1218: (107-125): Error trying to invoke SMT solver. +// Warning 1218: (114-119): CHC: Error trying to invoke SMT solver. +// Warning 1218: (107-125): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol b/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol index e8e388c15..7638d3e31 100644 --- a/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol +++ b/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol @@ -6,6 +6,6 @@ contract test { } // ---- // Warning 2072: (80-88): Unused local variable. -// Warning 4984: (91-112): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (91-112): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 5084: (91-100): Type conversion is not yet fully supported and might yield false positives. // Warning 5084: (103-112): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol b/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol index e4550c4db..046c54b54 100644 --- a/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol @@ -1,10 +1,13 @@ pragma experimental SMTChecker; + contract C { - bytes20 x; - function f(bytes16 b) public view { - b[uint8(x[2])]; + function f(uint i) public pure { + bytes memory x = hex"00112233"; + assert(x[0] == 0x00); + assert(x[1] == 0x11); + require(i > 3); + assert(x[i] == 0x00); } } // ---- -// Warning 7989: (116-120): Assertion checker does not yet support index accessing fixed bytes. -// Warning 7989: (108-122): Assertion checker does not yet support index accessing fixed bytes. +// Warning 6328: (215-235): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/index_access_for_bytesNN.sol b/test/libsolidity/smtCheckerTests/operators/index_access_for_bytesNN.sol new file mode 100644 index 000000000..65ea05950 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/index_access_for_bytesNN.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + bytes20 x; + function f(bytes16 b) public view { + b[uint8(x[2])]; + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/index_access_for_string.sol b/test/libsolidity/smtCheckerTests/operators/index_access_for_string.sol new file mode 100644 index 000000000..5f9f7e94a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/index_access_for_string.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint i) public pure { + string memory x = "\x12\x34"; + bytes memory y = bytes(x); + assert(y[0] == 0x12); + assert(y[1] == 0x34); + require(i > 2); + assert(y[i] == 0x00); + } +} +// ---- +// Warning 6328: (248-268): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/index_access_side_effect.sol b/test/libsolidity/smtCheckerTests/operators/index_access_side_effect.sol new file mode 100644 index 000000000..26336ed82 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/index_access_side_effect.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; + +contract C { + uint[] a; + function h() internal returns (uint[] storage) { + if (a[2] == 0) + a[2] = 3; + return a; + } + function g() public { + h()[2] = 4; + assert(h()[2] == 3); + } +} +// ---- +// Warning 6328: (191-210): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/integer_new.sol b/test/libsolidity/smtCheckerTests/operators/integer_new.sol new file mode 100644 index 000000000..53db42141 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/integer_new.sol @@ -0,0 +1,36 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + uint[] memory x = new uint[](0); + assert(x.length == 0); + } + function g() public pure { + uint[] memory x = new uint[](3); + assert(x.length == 3); + assert(x[0] == 0); + assert(x[1] == 0); + assert(x[2] == 0); + } + function h() public pure { + uint[] memory x = new uint[](3); + assert(x.length == 3); + x[0] = 0x12; + x[1] = 0x34; + assert(x[0] == 0x12); + assert(x[1] == 0x34); + // This should be an out-of-bounds assertion. + x[5] = 0xff; + assert(x[5] == 0xff); + } + function h(uint size) public pure { + uint[] memory x = new uint[](size); + assert(x.length == size); + require(size >= 2); + x[0] = 0x12; + x[1] = 0x34; + assert(x[0] == 0x12); + assert(x[1] == 0x34); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/mod.sol b/test/libsolidity/smtCheckerTests/operators/mod.sol index de7f7b135..0c5940052 100644 --- a/test/libsolidity/smtCheckerTests/operators/mod.sol +++ b/test/libsolidity/smtCheckerTests/operators/mod.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 1218: (166-182): Error trying to invoke SMT solver. +// Warning 1218: (166-182): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/mod_even.sol b/test/libsolidity/smtCheckerTests/operators/mod_even.sol index 9e8a9cd96..1b88e3fc5 100644 --- a/test/libsolidity/smtCheckerTests/operators/mod_even.sol +++ b/test/libsolidity/smtCheckerTests/operators/mod_even.sol @@ -9,5 +9,5 @@ contract C } } // ---- -// Warning 1218: (113-118): Error trying to invoke SMT solver. -// Warning 1218: (122-142): Error trying to invoke SMT solver. +// Warning 1218: (113-118): CHC: Error trying to invoke SMT solver. +// Warning 1218: (122-142): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/mod_n.sol b/test/libsolidity/smtCheckerTests/operators/mod_n.sol index fb3643107..81f5b6a66 100644 --- a/test/libsolidity/smtCheckerTests/operators/mod_n.sol +++ b/test/libsolidity/smtCheckerTests/operators/mod_n.sol @@ -9,4 +9,4 @@ contract C } } // ---- -// Warning 1218: (126-139): Error trying to invoke SMT solver. +// Warning 1218: (126-139): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/mod_n_uint16.sol b/test/libsolidity/smtCheckerTests/operators/mod_n_uint16.sol index 2231d7834..b219917d6 100644 --- a/test/libsolidity/smtCheckerTests/operators/mod_n_uint16.sol +++ b/test/libsolidity/smtCheckerTests/operators/mod_n_uint16.sol @@ -9,4 +9,4 @@ contract C } } // ---- -// Warning 1218: (130-149): Error trying to invoke SMT solver. +// Warning 1218: (130-149): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/compound_shift_left.sol b/test/libsolidity/smtCheckerTests/operators/shifts/compound_shift_left.sol new file mode 100644 index 000000000..442bd3a77 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/compound_shift_left.sol @@ -0,0 +1,15 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint256 a, uint256 b) internal pure returns (uint256) { + a <<= b; + return a; + } + function t() public pure { + assert(f(0x4266, 0x0) == 0x4266); + assert(f(0x4266, 0x8) == 0x426600); + assert(f(0x4266, 0xf0) == 0x4266000000000000000000000000000000000000000000000000000000000000); + assert(f(0x4266, 0x4266) == 0); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/compound_shift_right.sol b/test/libsolidity/smtCheckerTests/operators/shifts/compound_shift_right.sol new file mode 100644 index 000000000..75dc0fe0d --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/compound_shift_right.sol @@ -0,0 +1,15 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint256 a, uint256 b) internal pure returns (uint256) { + a >>= b; + return a; + } + function t() public pure { + assert(f(0x4266, 0) == 0x4266); + assert(f(0x4266, 0x8) == 0x42); + assert(f(0x4266, 0x11) == 0); + assert(f(57896044618658097711785492504343953926634992332820282019728792003956564819968, 5) == 1809251394333065553493296640760748560207343510400633813116524750123642650624); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_cleanup.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_cleanup.sol new file mode 100644 index 000000000..4c6708398 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_cleanup.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure returns (uint16 x) { + x = 0xffff; + x += 32; + x = x << 8; + x = x >> 16; + assert(x == 0); + // Fails because x = 0. + assert(x == 10); + } +} +// ---- +// Warning 4984: (109-116): CHC: Overflow (resulting value larger than 65535) happens here. +// Warning 6328: (193-208): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_left.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left.sol new file mode 100644 index 000000000..c489553fe --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint256 a, uint256 b) internal pure returns (uint256) { + return a << b; + } + function t() public pure { + assert(f(0x4266, 0x0) == 0x4266); + // Fails because the above is true. + assert(f(0x4266, 0x0) == 0x4268); + + assert(f(0x4266, 0x8) == 0x426600); + // Fails because the above is true. + assert(f(0x4266, 0x8) == 0x120939); + + assert(f(0x4266, 0xf0) == 0x4266000000000000000000000000000000000000000000000000000000000000); + // Fails because the above is true. + assert(f(0x4266, 0xf0) == 0x4266000000000000000000000000000000000000000000000000000000000001); + + assert(f(0x4266, 0x4266) == 0); + // Fails because the above is true. + assert(f(0x4266, 0x4266) == 1); + } +} +// ---- +// Warning 6328: (250-282): CHC: Assertion violation happens here. +// Warning 6328: (363-397): CHC: Assertion violation happens here. +// Warning 6328: (537-630): CHC: Assertion violation happens here. +// Warning 6328: (707-737): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_larger_type.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_larger_type.sol new file mode 100644 index 000000000..864cbcc00 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_larger_type.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure returns (int8) { + uint8 x = 254; + int8 y = 1; + assert(y << x == 0); + // Fails because z = 0. + assert(y << x == 10); + return y << x; + } +} +// ---- +// Warning 6328: (171-191): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_uint32.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_uint32.sol new file mode 100644 index 000000000..709de607e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_uint32.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint32 a, uint32 b) internal pure returns (uint256) { + return a << b; + } + function t() public pure { + assert(f(0x4266, 0) == 0x4266); + // Fails because the above is true. + assert(f(0x4266, 0) == 0x4267); + + assert(f(0x4266, 0x10) == 0x42660000); + // Fails because the above is true. + assert(f(0x4266, 0x10) == 0x426600000); + + assert(f(0x4266, 0x11) == 0x84cc0000); + // Fails because the above is true. + assert(f(0x4266, 0x11) == 0x84cc000); + + assert(f(0x4266, 0x20) == 0); + // Fails because the above is true. + assert(f(0x4266, 0x20) == 1); + } +} +// ---- +// Warning 6328: (246-276): CHC: Assertion violation happens here. +// Warning 6328: (360-398): CHC: Assertion violation happens here. +// Warning 6328: (482-518): CHC: Assertion violation happens here. +// Warning 6328: (593-621): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_uint8.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_uint8.sol new file mode 100644 index 000000000..03658f236 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_left_uint8.sol @@ -0,0 +1,19 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint8 a, uint8 b) internal pure returns (uint256) { + return a << b; + } + function t() public pure { + assert(f(0x66, 0x0) == 0x66); + // Fails because the above is true. + assert(f(0x66, 0x0) == 0x660); + + assert(f(0x66, 0x8) == 0); + // Fails because the above is true. + assert(f(0x66, 0x8) == 1); + } +} +// ---- +// Warning 6328: (242-271): CHC: Assertion violation happens here. +// Warning 6328: (343-368): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_overflow.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_overflow.sol new file mode 100644 index 000000000..e636b8968 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_overflow.sol @@ -0,0 +1,39 @@ +pragma experimental SMTChecker; + +contract C { + function leftU(uint8 x, uint8 y) internal pure returns (uint8) { + return x << y; + } + + function leftS(int8 x, uint8 y) internal pure returns (int8) { + return x << y; + } + + function t() public pure { + assert(leftU(255, 8) == 0); + // Fails because the above is true. + assert(leftU(255, 8) == 1); + + assert(leftU(255, 1) == 254); + // Fails because the above is true. + assert(leftU(255, 1) == 255); + + assert(leftU(255, 0) == 255); + // Fails because the above is true. + assert(leftU(255, 0) == 0); + + assert(leftS(1, 7) == -128); + // Fails because the above is true. + assert(leftS(1, 7) == 127); + + assert(leftS(1, 6) == 64); + // Fails because the above is true. + assert(leftS(1, 6) == -64); + } +} +// ---- +// Warning 6328: (340-366): CHC: Assertion violation happens here. +// Warning 6328: (441-469): CHC: Assertion violation happens here. +// Warning 6328: (544-570): CHC: Assertion violation happens here. +// Warning 6328: (644-670): CHC: Assertion violation happens here. +// Warning 6328: (742-768): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right.sol new file mode 100644 index 000000000..da8c52414 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint256 a, uint256 b) internal pure returns (uint256) { + return a >> b; + } + function t() public pure { + assert(f(0x4266, 0) == 0x4266); + // Fails because the above is true. + assert(f(0x4266, 0) == 0x426); + + assert(f(0x4266, 0x8) == 0x42); + // Fails because the above is true. + assert(f(0x4266, 0x8) == 0x420); + + assert(f(0x4266, 0x11) == 0); + // Fails because the above is true. + assert(f(0x4266, 0x11) == 1); + + assert(f(57896044618658097711785492504343953926634992332820282019728792003956564819968, 5) == 1809251394333065553493296640760748560207343510400633813116524750123642650624); + // Fails because the above is true. + assert(f(57896044618658097711785492504343953926634992332820282019728792003956564819968, 5) == 0); + } +} +// ---- +// Warning 6328: (248-277): CHC: Assertion violation happens here. +// Warning 6328: (354-385): CHC: Assertion violation happens here. +// Warning 6328: (460-488): CHC: Assertion violation happens here. +// Warning 6328: (706-802): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_literal.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_literal.sol new file mode 100644 index 000000000..4acb0dffd --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_literal.sol @@ -0,0 +1,40 @@ +pragma experimental SMTChecker; + +contract C { + function f(int16 x, uint16 y, int16 z) internal pure returns (bool) { + return x >> y == z; + } + + function t() public pure { + assert(f(-4266, 0, -4266)); + // Fails because the above is true. + assert(f(-4266, 0, -426)); + + assert(f(-4266, 1, -2133)); + // Fails because the above is true. + assert(f(-4266, 1, -2134)); + + assert(f(-4266, 4, -267)); + // Fails because the above is true. + assert(f(-4266, 4, -2670)); + + assert(f(-4266, 8, -17)); + // Fails because the above is true. + assert(f(-4266, 8, -1)); + + assert(f(-4266, 16, -1)); + // Fails because the above is true. + assert(f(-4266, 16, -0)); + + assert(f(-4266, 17, -1)); + // Fails because the above is true. + assert(f(-4266, 17, -0)); + } +} +// ---- +// Warning 6328: (241-266): CHC: Assertion violation happens here. +// Warning 6328: (339-365): CHC: Assertion violation happens here. +// Warning 6328: (437-463): CHC: Assertion violation happens here. +// Warning 6328: (534-557): CHC: Assertion violation happens here. +// Warning 6328: (628-652): CHC: Assertion violation happens here. +// Warning 6328: (723-747): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue.sol new file mode 100644 index 000000000..79a0eeedf --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue.sol @@ -0,0 +1,40 @@ +pragma experimental SMTChecker; + +contract C { + function f(int256 a, uint256 b) internal pure returns (int256) { + return a >> b; + } + function t() public pure { + assert(f(-4266, 0) == -4266); + // Fails because the above is true. + assert(f(-4266, 0) == -426); + + assert(f(-4266, 1) == -2133); + // Fails because the above is true. + assert(f(-4266, 1) == -21330); + + assert(f(-4266, 4) == -267); + // Fails because the above is true. + assert(f(-4266, 4) == -255); + + assert(f(-4266, 8) == -17); + // Fails because the above is true. + assert(f(-4266, 8) == -1); + + assert(f(-4266, 16) == -1); + // Fails because the above is true. + assert(f(-4266, 16) == 0); + + assert(f(-4266, 17) == -1); + // Fails because the above is true. + assert(f(-4266, 17) == 0); + } + +} +// ---- +// Warning 6328: (244-271): CHC: Assertion violation happens here. +// Warning 6328: (346-375): CHC: Assertion violation happens here. +// Warning 6328: (449-476): CHC: Assertion violation happens here. +// Warning 6328: (549-574): CHC: Assertion violation happens here. +// Warning 6328: (647-672): CHC: Assertion violation happens here. +// Warning 6328: (745-770): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int16.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int16.sol new file mode 100644 index 000000000..28008e6de --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int16.sol @@ -0,0 +1,39 @@ +pragma experimental SMTChecker; + +contract C { + function f(int16 a, uint16 b) internal pure returns (int256) { + return a >> b; + } + function t() public pure { + assert(f(-4266, 0) == -4266); + // Fails because the above is true. + assert(f(-4266, 0) == -426); + + assert(f(-4266, 1) == -2133); + // Fails because the above is true. + assert(f(-4266, 1) == -21330); + + assert(f(-4266, 4) == -267); + // Fails because the above is true. + assert(f(-4266, 4) == -255); + + assert(f(-4266, 8) == -17); + // Fails because the above is true. + assert(f(-4266, 8) == -1); + + assert(f(-4266, 16) == -1); + // Fails because the above is true. + assert(f(-4266, 16) == 0); + + assert(f(-4266, 17) == -1); + // Fails because the above is true. + assert(f(-4266, 17) == 0); + } +} +// ---- +// Warning 6328: (242-269): CHC: Assertion violation happens here. +// Warning 6328: (344-373): CHC: Assertion violation happens here. +// Warning 6328: (447-474): CHC: Assertion violation happens here. +// Warning 6328: (547-572): CHC: Assertion violation happens here. +// Warning 6328: (645-670): CHC: Assertion violation happens here. +// Warning 6328: (743-768): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int32.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int32.sol new file mode 100644 index 000000000..62332e446 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int32.sol @@ -0,0 +1,39 @@ +pragma experimental SMTChecker; + +contract C { + function f(int32 a, uint32 b) internal pure returns (int256) { + return a >> b; + } + function t() public pure { + assert(f(-4266, 0) == -4266); + // Fails because the above is true. + assert(f(-4266, 0) == -426); + + assert(f(-4266, 1) == -2133); + // Fails because the above is true. + assert(f(-4266, 1) == -21330); + + assert(f(-4266, 4) == -267); + // Fails because the above is true. + assert(f(-4266, 4) == -255); + + assert(f(-4266, 8) == -17); + // Fails because the above is true. + assert(f(-4266, 8) == -1); + + assert(f(-4266, 16) == -1); + // Fails because the above is true. + assert(f(-4266, 16) == 0); + + assert(f(-4266, 17) == -1); + // Fails because the above is true. + assert(f(-4266, 17) == 0); + } +} +// ---- +// Warning 6328: (242-269): CHC: Assertion violation happens here. +// Warning 6328: (344-373): CHC: Assertion violation happens here. +// Warning 6328: (447-474): CHC: Assertion violation happens here. +// Warning 6328: (547-572): CHC: Assertion violation happens here. +// Warning 6328: (645-670): CHC: Assertion violation happens here. +// Warning 6328: (743-768): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int8.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int8.sol new file mode 100644 index 000000000..103bf22d3 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_negative_lvalue_int8.sol @@ -0,0 +1,39 @@ +pragma experimental SMTChecker; + +contract C { + function f(int8 a, uint8 b) internal pure returns (int256) { + return a >> b; + } + function t() public pure { + assert(f(-66, 0) == -66); + // Fails because the above is true. + assert(f(-66, 0) == -6); + + assert(f(-66, 1) == -33); + // Fails because the above is true. + assert(f(-66, 1) == -3); + + assert(f(-66, 4) == -5); + // Fails because the above is true. + assert(f(-66, 4) == -2); + + assert(f(-66, 8) == -1); + // Fails because the above is true. + assert(f(-66, 8) == -2); + + assert(f(-66, 16) == -1); + // Fails because the above is true. + assert(f(-66, 16) == 0); + + assert(f(-66, 17) == -1); + // Fails because the above is true. + assert(f(-66, 17) == 0); + } +} +// ---- +// Warning 6328: (236-259): CHC: Assertion violation happens here. +// Warning 6328: (330-353): CHC: Assertion violation happens here. +// Warning 6328: (423-446): CHC: Assertion violation happens here. +// Warning 6328: (516-539): CHC: Assertion violation happens here. +// Warning 6328: (610-633): CHC: Assertion violation happens here. +// Warning 6328: (704-727): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_uint32.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_uint32.sol new file mode 100644 index 000000000..1d7269f6c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_uint32.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint32 a, uint32 b) internal pure returns (uint256) { + return a >> b; + } + function t() public pure { + assert(f(0x4266, 0) == 0x4266); + // Fails because the above is true. + assert(f(0x4266, 0) == 0x426); + + assert(f(0x4266, 8) == 0x42); + // Fails because the above is true. + assert(f(0x4266, 8) == 0x420); + + assert(f(0x4266, 0x10) == 0); + // Fails because the above is true. + assert(f(0x4266, 0x10) == 255); + + assert(f(0x4266, 0x11) == 0); + // Fails because the above is true. + assert(f(0x4266, 0x11) == 255); + } +} +// ---- +// Warning 6328: (246-275): CHC: Assertion violation happens here. +// Warning 6328: (350-379): CHC: Assertion violation happens here. +// Warning 6328: (454-484): CHC: Assertion violation happens here. +// Warning 6328: (559-589): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_uint8.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_uint8.sol new file mode 100644 index 000000000..677f97081 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_right_uint8.sol @@ -0,0 +1,19 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint8 a, uint8 b) internal pure returns (uint256) { + return a >> b; + } + function t() public pure { + assert(f(0x66, 0) == 0x66); + // Fails because the above is true. + assert(f(0x66, 0) == 0x6); + + assert(f(0x66, 8) == 0); + // Fails because the above is true. + assert(f(0x66, 8) == 1); + } +} +// ---- +// Warning 6328: (240-265): CHC: Assertion violation happens here. +// Warning 6328: (335-358): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/shifts/shift_underflow_negative_rvalue.sol b/test/libsolidity/smtCheckerTests/operators/shifts/shift_underflow_negative_rvalue.sol new file mode 100644 index 000000000..56591e697 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/shifts/shift_underflow_negative_rvalue.sol @@ -0,0 +1,24 @@ +pragma experimental SMTChecker; + +contract C { + function f(int256 a, uint256 b) internal pure returns (int256) { + return a << b; + } + + function g(int256 a, uint256 b) internal pure returns (int256) { + return a >> b; + } + + function t() public pure { + assert(f(1, 2**256 - 1) == 0); + // Fails because the above is true. + assert(f(1, 2**256 - 1) == 1); + + assert(g(1, 2**256 - 1) == 0); + // Fails because the above is true. + assert(g(1, 2**256 - 1) == 1); + } +} +// ---- +// Warning 6328: (345-374): CHC: Assertion violation happens here. +// Warning 6328: (450-479): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_add.sol b/test/libsolidity/smtCheckerTests/operators/unary_add.sol index 1a1ae611d..daa8c793c 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_add.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_add.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (194-207): Assertion violation happens here +// Warning 6328: (194-207): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_add_array.sol b/test/libsolidity/smtCheckerTests/operators/unary_add_array.sol index 96e43ff8f..401e4af62 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_add_array.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_add_array.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6328: (240-253): Assertion violation happens here +// Warning 6328: (240-253): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_add_mapping.sol b/test/libsolidity/smtCheckerTests/operators/unary_add_mapping.sol index cdf4cbdbd..38dcb98b7 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_add_mapping.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_add_mapping.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6328: (244-257): Assertion violation happens here +// Warning 6328: (244-257): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_operators_tuple_3.sol b/test/libsolidity/smtCheckerTests/operators/unary_operators_tuple_3.sol index 6ab61f0ee..a71e0aaf3 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_operators_tuple_3.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_operators_tuple_3.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (140-150): Assertion violation happens here +// Warning 6328: (140-150): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_sub.sol b/test/libsolidity/smtCheckerTests/operators/unary_sub.sol index dba43ac87..ee2bffc2c 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_sub.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_sub.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (194-207): Assertion violation happens here +// Warning 6328: (194-207): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_sub_array.sol b/test/libsolidity/smtCheckerTests/operators/unary_sub_array.sol index 73393df91..b16168223 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_sub_array.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_sub_array.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6328: (240-253): Assertion violation happens here +// Warning 6328: (240-253): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/unary_sub_mapping.sol b/test/libsolidity/smtCheckerTests/operators/unary_sub_mapping.sol index 22191a935..e7eedc11f 100644 --- a/test/libsolidity/smtCheckerTests/operators/unary_sub_mapping.sol +++ b/test/libsolidity/smtCheckerTests/operators/unary_sub_mapping.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 6328: (244-257): Assertion violation happens here +// Warning 6328: (244-257): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/overflow_mul.sol b/test/libsolidity/smtCheckerTests/overflow/overflow_mul.sol index 05b15987f..69f807a5d 100644 --- a/test/libsolidity/smtCheckerTests/overflow/overflow_mul.sol +++ b/test/libsolidity/smtCheckerTests/overflow/overflow_mul.sol @@ -13,5 +13,5 @@ contract C } } // ---- -// Warning 4984: (120-125): Overflow (resulting value larger than 255) happens here -// Warning 4984: (163-168): Overflow (resulting value larger than 255) happens here +// Warning 4984: (120-125): CHC: Overflow (resulting value larger than 255) happens here. +// Warning 4984: (163-168): CHC: Overflow (resulting value larger than 255) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/overflow_mul_signed.sol b/test/libsolidity/smtCheckerTests/overflow/overflow_mul_signed.sol index 7a71a7d2f..9b2ef0a08 100644 --- a/test/libsolidity/smtCheckerTests/overflow/overflow_mul_signed.sol +++ b/test/libsolidity/smtCheckerTests/overflow/overflow_mul_signed.sol @@ -12,5 +12,5 @@ contract C } } // ---- -// Warning 4984: (117-122): Overflow (resulting value larger than 127) happens here -// Warning 4984: (150-157): Overflow (resulting value larger than 127) happens here +// Warning 4984: (117-122): CHC: Overflow (resulting value larger than 127) happens here. +// Warning 4984: (150-157): CHC: Overflow (resulting value larger than 127) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol b/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol index c94b09b97..61fa7839c 100644 --- a/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol +++ b/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol @@ -14,5 +14,5 @@ contract C } } // ---- -// Warning 4984: (154-159): Overflow (resulting value larger than 255) happens here -// Warning 4984: (185-192): Overflow (resulting value larger than 255) happens here +// Warning 4984: (154-159): CHC: Overflow (resulting value larger than 255) happens here. +// Warning 4984: (185-192): CHC: Overflow (resulting value larger than 255) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/overflow_sum_signed.sol b/test/libsolidity/smtCheckerTests/overflow/overflow_sum_signed.sol index 8fc6b4997..473c12447 100644 --- a/test/libsolidity/smtCheckerTests/overflow/overflow_sum_signed.sol +++ b/test/libsolidity/smtCheckerTests/overflow/overflow_sum_signed.sol @@ -14,6 +14,6 @@ contract C } } // ---- -// Warning 4984: (117-122): Overflow (resulting value larger than 127) happens here -// Warning 4984: (151-158): Overflow (resulting value larger than 127) happens here -// Warning 3944: (197-205): Underflow (resulting value less than -128) happens here +// Warning 4984: (117-122): CHC: Overflow (resulting value larger than 127) happens here. +// Warning 4984: (151-158): CHC: Overflow (resulting value larger than 127) happens here. +// Warning 3944: (197-205): CHC: Underflow (resulting value less than -128) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_div_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_div_overflow.sol index fb14d7694..a7fd99e15 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_div_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_div_overflow.sol @@ -6,6 +6,6 @@ contract C { } } // ---- -// Warning 1218: (110-115): Error trying to invoke SMT solver. -// Warning 3046: (110-115): Division by zero happens here -// Warning 2661: (110-115): Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here +// Warning 1218: (110-115): CHC: Error trying to invoke SMT solver. +// Warning 3046: (110-115): BMC: Division by zero happens here. +// Warning 2661: (110-115): BMC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sub_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sub_overflow.sol index a27c709cd..380ccb71a 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sub_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sub_overflow.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 4984: (129-134): Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here +// Warning 4984: (129-134): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol index a834311cf..84b0f3f42 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol @@ -7,5 +7,5 @@ contract C { } } // ---- -// Warning 3944: (111-116): Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here -// Warning 3944: (133-138): Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here +// Warning 3944: (111-116): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 3944: (133-138): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_mod_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_mod_overflow.sol index d773af2f6..df275044b 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_mod_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_mod_overflow.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// Warning 3046: (110-115): Division by zero happens here +// Warning 3046: (110-115): BMC: Division by zero happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol index 34cc55a7b..fc9b41d1b 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol @@ -6,5 +6,5 @@ contract C { } } // ---- -// Warning 3944: (110-115): Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here -// Warning 4984: (110-115): Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here +// Warning 3944: (110-115): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 4984: (110-115): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol index 4a207c53f..2b34c15e4 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol @@ -6,5 +6,5 @@ contract C { } } // ---- -// Warning 3944: (110-115): Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here -// Warning 4984: (110-115): Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here +// Warning 3944: (110-115): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 4984: (110-115): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol index 3edc402eb..19fcbc999 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol @@ -6,5 +6,5 @@ contract C { } } // ---- -// Warning 3944: (110-115): Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here -// Warning 4984: (110-115): Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here +// Warning 3944: (110-115): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 4984: (110-115): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol index 41ba3d0d5..5507cc098 100644 --- a/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol @@ -3,4 +3,4 @@ contract C { function f(uint a, uint b) public pure returns (uint) { return a + b; } } // ---- -// Warning 4984: (112-117): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (112-117): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/underflow_sub.sol b/test/libsolidity/smtCheckerTests/overflow/underflow_sub.sol index 1ecf1e870..5be032d92 100644 --- a/test/libsolidity/smtCheckerTests/overflow/underflow_sub.sol +++ b/test/libsolidity/smtCheckerTests/overflow/underflow_sub.sol @@ -12,5 +12,5 @@ contract C } } // ---- -// Warning 3944: (117-122): Underflow (resulting value less than 0) happens here -// Warning 3944: (150-157): Underflow (resulting value less than 0) happens here +// Warning 3944: (117-122): CHC: Underflow (resulting value less than 0) happens here. +// Warning 3944: (150-157): CHC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/underflow_sub_signed.sol b/test/libsolidity/smtCheckerTests/overflow/underflow_sub_signed.sol index 6dab43c79..50713adb4 100644 --- a/test/libsolidity/smtCheckerTests/overflow/underflow_sub_signed.sol +++ b/test/libsolidity/smtCheckerTests/overflow/underflow_sub_signed.sol @@ -16,6 +16,6 @@ contract C } } // ---- -// Warning 3944: (116-123): Underflow (resulting value less than -128) happens here -// Warning 3944: (163-170): Underflow (resulting value less than -128) happens here -// Warning 4984: (207-217): Overflow (resulting value larger than 127) happens here +// Warning 3944: (116-123): CHC: Underflow (resulting value less than -128) happens here. +// Warning 3944: (163-170): CHC: Underflow (resulting value less than -128) happens here. +// Warning 4984: (207-217): CHC: Overflow (resulting value larger than 127) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/unsigned_div_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/unsigned_div_overflow.sol index 01eeb27ac..e8a5dc76a 100644 --- a/test/libsolidity/smtCheckerTests/overflow/unsigned_div_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/unsigned_div_overflow.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// Warning 3046: (113-118): Division by zero happens here +// Warning 3046: (113-118): BMC: Division by zero happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/unsigned_mod_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/unsigned_mod_overflow.sol index 327e2bdcc..59bb034c5 100644 --- a/test/libsolidity/smtCheckerTests/overflow/unsigned_mod_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/unsigned_mod_overflow.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// Warning 3046: (113-118): Division by zero happens here +// Warning 3046: (113-118): BMC: Division by zero happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/unsigned_mul_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/unsigned_mul_overflow.sol index bf7b697e8..aa2d02d2e 100644 --- a/test/libsolidity/smtCheckerTests/overflow/unsigned_mul_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/unsigned_mul_overflow.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// Warning 4984: (113-118): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (113-118): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/unsigned_sub_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/unsigned_sub_overflow.sol index 6a44c893b..52e112f9d 100644 --- a/test/libsolidity/smtCheckerTests/overflow/unsigned_sub_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/unsigned_sub_overflow.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// Warning 3944: (113-118): Underflow (resulting value less than 0) happens here +// Warning 3944: (113-118): CHC: Underflow (resulting value less than 0) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/unsigned_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/unsigned_sum_overflow.sol index b0632ef48..58db35b5b 100644 --- a/test/libsolidity/smtCheckerTests/overflow/unsigned_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/unsigned_sum_overflow.sol @@ -6,4 +6,4 @@ contract C { } } // ---- -// Warning 4984: (113-118): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (113-118): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol b/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol index 513166872..26d17231e 100644 --- a/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol +++ b/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol @@ -2,15 +2,13 @@ pragma experimental SMTChecker; pragma experimental "ABIEncoderV2"; contract C { - struct S { uint x; uint[] b; } - function f() public pure returns (S memory, bytes memory, uint[][2] memory) { - return abi.decode("abc", (S, bytes, uint[][2])); - } + struct S { uint x; uint[] b; } + function f() public pure returns (S memory, bytes memory, uint[][2] memory) { + return abi.decode("abc", (S, bytes, uint[][2])); + } } // ---- -// Warning 8115: (151-159): Assertion checker does not yet support the type of this variable. -// Warning 8364: (206-209): Assertion checker does not yet implement type abi -// Warning 8364: (225-226): Assertion checker does not yet implement type type(struct C.S storage pointer) -// Warning 8364: (235-241): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (235-244): Assertion checker does not yet implement type type(uint256[] memory[2] memory) -// Warning 4588: (206-246): Assertion checker does not yet implement this type of function call. +// Warning 8364: (221-222): Assertion checker does not yet implement type type(struct C.S storage pointer) +// Warning 8364: (231-237): Assertion checker does not yet implement type type(uint256[] memory) +// Warning 8364: (231-240): Assertion checker does not yet implement type type(uint256[] memory[2] memory) +// Warning 4588: (202-242): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2_value_types.sol b/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2_value_types.sol index 066a861e4..8fa353ec9 100644 --- a/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2_value_types.sol +++ b/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2_value_types.sol @@ -2,18 +2,16 @@ pragma experimental SMTChecker; pragma experimental "ABIEncoderV2"; contract C { - function f() public pure { - (uint x1, bool b1) = abi.decode("abc", (uint, bool)); - (uint x2, bool b2) = abi.decode("abc", (uint, bool)); - // False positive until abi.* are implemented as uninterpreted functions. - assert(x1 == x2); - } + function f() public pure { + (uint x1, bool b1) = abi.decode("abc", (uint, bool)); + (uint x2, bool b2) = abi.decode("abc", (uint, bool)); + // False positive until abi.* are implemented as uninterpreted functions. + assert(x1 == x2); + } } // ---- -// Warning 2072: (125-132): Unused local variable. -// Warning 2072: (183-190): Unused local variable. -// Warning 6328: (303-319): Assertion violation happens here -// Warning 8364: (136-139): Assertion checker does not yet implement type abi -// Warning 4588: (136-167): Assertion checker does not yet implement this type of function call. -// Warning 8364: (194-197): Assertion checker does not yet implement type abi -// Warning 4588: (194-225): Assertion checker does not yet implement this type of function call. +// Warning 2072: (122-129): Unused local variable. +// Warning 2072: (178-185): Unused local variable. +// Warning 6328: (300-316): CHC: Assertion violation happens here. +// Warning 4588: (133-164): Assertion checker does not yet implement this type of function call. +// Warning 4588: (189-220): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol b/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol index 1715fa4e0..4ba6b7211 100644 --- a/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol +++ b/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol @@ -1,24 +1,21 @@ pragma experimental SMTChecker; contract C { - function f() public pure { - (uint a1, bytes32 b1, C c1) = abi.decode("abc", (uint, bytes32, C)); - (uint a2, bytes32 b2, C c2) = abi.decode("abc", (uint, bytes32, C)); - // False positive until abi.* are implemented as uninterpreted functions. - assert(a1 == a2); - assert(a1 != a2); - } - + function f() public pure { + (uint a1, bytes32 b1, C c1) = abi.decode("abc", (uint, bytes32, C)); + (uint a2, bytes32 b2, C c2) = abi.decode("abc", (uint, bytes32, C)); + // False positive until abi.* are implemented as uninterpreted functions. + assert(a1 == a2); + assert(a1 != a2); + } } // ---- -// Warning 2072: (88-98): Unused local variable. -// Warning 2072: (100-104): Unused local variable. -// Warning 2072: (161-171): Unused local variable. -// Warning 2072: (173-177): Unused local variable. -// Warning 6328: (296-312): Assertion violation happens here -// Warning 6328: (315-331): Assertion violation happens here -// Warning 8364: (108-111): Assertion checker does not yet implement type abi -// Warning 8364: (142-143): Assertion checker does not yet implement type type(contract C) -// Warning 4588: (108-145): Assertion checker does not yet implement this type of function call. -// Warning 8364: (181-184): Assertion checker does not yet implement type abi -// Warning 8364: (215-216): Assertion checker does not yet implement type type(contract C) -// Warning 4588: (181-218): Assertion checker does not yet implement this type of function call. +// Warning 2072: (85-95): Unused local variable. +// Warning 2072: (97-101): Unused local variable. +// Warning 2072: (156-166): Unused local variable. +// Warning 2072: (168-172): Unused local variable. +// Warning 6328: (293-309): CHC: Assertion violation happens here. +// Warning 6328: (313-329): CHC: Assertion violation happens here. +// Warning 8364: (139-140): Assertion checker does not yet implement type type(contract C) +// Warning 4588: (105-142): Assertion checker does not yet implement this type of function call. +// Warning 8364: (210-211): Assertion checker does not yet implement type type(contract C) +// Warning 4588: (176-213): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/special/abi_encode_slice.sol b/test/libsolidity/smtCheckerTests/special/abi_encode_slice.sol new file mode 100644 index 000000000..6a61a2618 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/abi_encode_slice.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +contract C { + function f(bytes calldata data) external pure returns (bytes memory) { + return abi.encode(bytes(data[:32])); + } +} +// ---- +// Warning 2923: (143-152): Assertion checker does not yet implement this expression. +// Warning 4588: (126-154): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/special/blockhash.sol b/test/libsolidity/smtCheckerTests/special/blockhash.sol index d08e056e7..ca956e6d3 100644 --- a/test/libsolidity/smtCheckerTests/special/blockhash.sol +++ b/test/libsolidity/smtCheckerTests/special/blockhash.sol @@ -10,6 +10,6 @@ contract C } } // ---- -// Warning 6328: (85-109): Assertion violation happens here -// Warning 6328: (113-137): Assertion violation happens here -// Warning 6328: (155-191): Assertion violation happens here +// Warning 6328: (85-109): CHC: Assertion violation happens here. +// Warning 6328: (113-137): CHC: Assertion violation happens here. +// Warning 6328: (155-191): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/difficulty.sol b/test/libsolidity/smtCheckerTests/special/difficulty.sol index 90e43e204..0e925fff7 100644 --- a/test/libsolidity/smtCheckerTests/special/difficulty.sol +++ b/test/libsolidity/smtCheckerTests/special/difficulty.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (91-129): Assertion violation happens here +// Warning 6328: (91-129): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/event.sol b/test/libsolidity/smtCheckerTests/special/event.sol new file mode 100644 index 000000000..b804370c9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/event.sol @@ -0,0 +1,28 @@ +pragma experimental SMTChecker; + +contract C { + event Nudge(); + event SomeArgs(uint, uint); + event Caller(address, uint); + function f() payable external { + emit Nudge(); + emit SomeArgs(134, 567); + emit Caller(msg.sender, msg.value); + } + function g_data() pure internal returns (uint) { + assert(true); + } + function g() external { + emit SomeArgs(g_data(), g_data()); + } + bool x = true; + function h_data() view internal returns (uint) { + assert(x); + } + function h() external { + x = false; + emit SomeArgs(h_data(), h_data()); + } +} +// ---- +// Warning 6328: (440-449): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/gasleft.sol b/test/libsolidity/smtCheckerTests/special/gasleft.sol index 0b14ee4e7..e8da03bed 100644 --- a/test/libsolidity/smtCheckerTests/special/gasleft.sol +++ b/test/libsolidity/smtCheckerTests/special/gasleft.sol @@ -10,5 +10,5 @@ contract C } } // ---- -// Warning 6328: (76-97): Assertion violation happens here -// Warning 6328: (123-144): Assertion violation happens here +// Warning 6328: (76-97): CHC: Assertion violation happens here. +// Warning 6328: (123-144): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/log.sol b/test/libsolidity/smtCheckerTests/special/log.sol new file mode 100644 index 000000000..86a36a3c9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/log.sol @@ -0,0 +1,39 @@ +pragma experimental SMTChecker; + +contract C { + function f() external { + bytes32 t1 = bytes32(uint256(0x1234)); + log0(t1); + log1(t1, t1); + log2(t1, t1, t1); + log3(t1, t1, t1, t1); + log4(t1, t1, t1, t1, t1); + } + function g_data() pure internal returns (bytes32) { + assert(true); + return bytes32(uint256(0x5678)); + } + function g() external { + // To test that the function call is actually visited. + log0(g_data()); + log1(g_data(), g_data()); + log2(g_data(), g_data(), g_data()); + log3(g_data(), g_data(), g_data(), g_data()); + log4(g_data(), g_data(), g_data(), g_data(), g_data()); + } + bool x = true; + function h_data() view internal returns (bytes32) { + assert(x); + } + function h() external { + // To test that the function call is actually visited. + x = false; + log0(h_data()); + log1(h_data(), h_data()); + log2(h_data(), h_data(), h_data()); + log3(h_data(), h_data(), h_data(), h_data()); + log4(h_data(), h_data(), h_data(), h_data(), h_data()); + } +} +// ---- +// Warning 6328: (668-677): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/many.sol b/test/libsolidity/smtCheckerTests/special/many.sol index 2e9b3c79a..5b16533dc 100644 --- a/test/libsolidity/smtCheckerTests/special/many.sol +++ b/test/libsolidity/smtCheckerTests/special/many.sol @@ -15,12 +15,12 @@ contract C } } // ---- -// Warning 4984: (311-316): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (79-115): Assertion violation happens here -// Warning 6328: (119-161): Assertion violation happens here -// Warning 6328: (165-204): Assertion violation happens here -// Warning 6328: (208-240): Assertion violation happens here -// Warning 6328: (244-275): Assertion violation happens here -// Warning 6328: (304-332): Assertion violation happens here -// Warning 6328: (336-364): Assertion violation happens here -// Warning 6328: (368-391): Assertion violation happens here +// Warning 4984: (311-316): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (79-115): CHC: Assertion violation happens here. +// Warning 6328: (119-161): CHC: Assertion violation happens here. +// Warning 6328: (165-204): CHC: Assertion violation happens here. +// Warning 6328: (208-240): CHC: Assertion violation happens here. +// Warning 6328: (244-275): CHC: Assertion violation happens here. +// Warning 6328: (304-332): CHC: Assertion violation happens here. +// Warning 6328: (336-364): CHC: Assertion violation happens here. +// Warning 6328: (368-391): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/msg_data.sol b/test/libsolidity/smtCheckerTests/special/msg_data.sol index 3936af6dd..4c5b24601 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_data.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_data.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (79-106): Assertion violation happens here +// Warning 6328: (79-106): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol b/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol index df5620d8b..65a5b2bc7 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol @@ -10,4 +10,3 @@ contract C } } // ---- -// Warning 5084: (98-108): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol b/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol index 91aa8d2c9..43871fb6a 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (155-178): Assertion violation happens here +// Warning 6328: (155-178): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/msg_sig.sol b/test/libsolidity/smtCheckerTests/special/msg_sig.sol index e3c86f5aa..4a7ddacc4 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_sig.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_sig.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (79-108): Assertion violation happens here +// Warning 6328: (79-108): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/this.sol b/test/libsolidity/smtCheckerTests/special/this.sol index 59c5f2d96..06e47f661 100644 --- a/test/libsolidity/smtCheckerTests/special/this.sol +++ b/test/libsolidity/smtCheckerTests/special/this.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (85-111): Assertion violation happens here +// Warning 6328: (85-111): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/typecast/address_literal.sol b/test/libsolidity/smtCheckerTests/typecast/address_literal.sol new file mode 100644 index 000000000..e6206f50f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/typecast/address_literal.sol @@ -0,0 +1,25 @@ +pragma experimental SMTChecker; + +contract C { + address x; // We know that this is "zero initialised". + function f() public view { + address a = address(0); + assert(x == address(0)); + assert(x == a); + } + + function g() public pure { + address a = address(0); + address b = address(1); + address c = address(0); + address d = a; + address e = address(0x12345678); + assert(c == d); + assert(a == c); + assert(e == address(305419896)); + // This is untrue. + assert(a == b); + } +} +// ---- +// Warning 6328: (487-501): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_address_1.sol b/test/libsolidity/smtCheckerTests/typecast/cast_address_1.sol index 0bce016c9..c76e4a9c7 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_address_1.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_address_1.sol @@ -8,5 +8,3 @@ contract C } } // ---- -// Warning 5084: (98-108): Type conversion is not yet fully supported and might yield false positives. -// Warning 5084: (125-135): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_different_size_1.sol b/test/libsolidity/smtCheckerTests/typecast/cast_different_size_1.sol index bde664225..e295f083f 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_different_size_1.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_different_size_1.sol @@ -18,9 +18,9 @@ contract C } } // ---- -// Warning 6328: (280-303): Assertion violation happens here -// Warning 6328: (414-431): Assertion violation happens here -// Warning 6328: (542-559): Assertion violation happens here +// Warning 6328: (280-303): CHC: Assertion violation happens here. +// Warning 6328: (414-431): CHC: Assertion violation happens here. +// Warning 6328: (542-559): CHC: Assertion violation happens here. // Warning 5084: (186-195): Type conversion is not yet fully supported and might yield false positives. // Warning 5084: (317-333): Type conversion is not yet fully supported and might yield false positives. // Warning 5084: (451-460): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_larger_2_fail.sol b/test/libsolidity/smtCheckerTests/typecast/cast_larger_2_fail.sol index d5cf22e3f..cfda2b639 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_larger_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_larger_2_fail.sol @@ -9,5 +9,5 @@ contract C } } // ---- -// Warning 6328: (149-163): Assertion violation happens here +// Warning 6328: (149-163): CHC: Assertion violation happens here. // Warning 5084: (108-117): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol b/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol index 1bb3b7463..60879207d 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol @@ -12,6 +12,6 @@ contract C } } // ---- -// Warning 6328: (207-230): Assertion violation happens here -// Warning 6328: (273-287): Assertion violation happens here +// Warning 6328: (207-230): CHC: Assertion violation happens here. +// Warning 6328: (273-287): CHC: Assertion violation happens here. // Warning 5084: (108-117): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_smaller_2.sol b/test/libsolidity/smtCheckerTests/typecast/cast_smaller_2.sol index f6adcf0ce..da8550034 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_smaller_2.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_smaller_2.sol @@ -10,5 +10,5 @@ contract C } } // ---- -// Warning 6328: (208-227): Assertion violation happens here +// Warning 6328: (208-227): CHC: Assertion violation happens here. // Warning 5084: (112-121): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_smaller_3.sol b/test/libsolidity/smtCheckerTests/typecast/cast_smaller_3.sol index 2d6cbada4..343e80e12 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_smaller_3.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_smaller_3.sol @@ -10,5 +10,5 @@ contract C } } // ---- -// Warning 6328: (198-215): Assertion violation happens here +// Warning 6328: (198-215): CHC: Assertion violation happens here. // Warning 5084: (108-117): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/enum_from_uint.sol b/test/libsolidity/smtCheckerTests/typecast/enum_from_uint.sol index 28b845fb6..ef115ebd2 100644 --- a/test/libsolidity/smtCheckerTests/typecast/enum_from_uint.sol +++ b/test/libsolidity/smtCheckerTests/typecast/enum_from_uint.sol @@ -10,6 +10,6 @@ contract C } } // ---- -// Warning 6328: (140-160): Assertion violation happens here +// Warning 6328: (140-160): CHC: Assertion violation happens here. // Warning 8364: (132-133): Assertion checker does not yet implement type type(enum C.D) // Warning 5084: (132-136): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_external.sol b/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_external.sol index 16eda0216..666574d90 100644 --- a/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_external.sol +++ b/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_external.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// Warning 6328: (155-175): Assertion violation happens here +// Warning 6328: (155-175): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol b/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol index 1f6869a1c..dcf0a6f5f 100644 --- a/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol +++ b/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol @@ -11,8 +11,8 @@ contract C { } } // ---- -// Warning 6328: (207-227): Assertion violation happens here -// Warning 6328: (231-245): Assertion violation happens here +// Warning 6328: (207-227): CHC: Assertion violation happens here. +// Warning 6328: (231-245): CHC: Assertion violation happens here. // Warning 5729: (214-218): Assertion checker does not yet implement this type of function call. // Warning 5729: (222-226): Assertion checker does not yet implement this type of function call. // Warning 7229: (238-244): Assertion checker does not yet implement the type function (uint256) returns (uint256) for comparisons diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol index 3bfd2b751..8e1de8b9a 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol @@ -9,5 +9,5 @@ contract B { } } // ---- -// Warning 6328: (162-184): Assertion violation happens here -// Warning 6328: (136-158): Assertion violation happens here +// Warning 6328: (162-184): CHC: Assertion violation happens here. +// Warning 6328: (136-158): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol index b4a482437..e9f40fe61 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol @@ -8,4 +8,4 @@ contract B { } } // ---- -// Warning 6328: (152-174): Assertion violation happens here +// Warning 6328: (152-174): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return.sol index 3042084e6..ca9028e66 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (238-259): Assertion violation happens here +// Warning 6328: (238-259): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol index c29efb6f5..28f41d183 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol @@ -12,4 +12,4 @@ contract C { } } // ---- -// Warning 6328: (442-461): Assertion violation happens here +// Warning 6328: (442-461): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_balance.sol b/test/libsolidity/smtCheckerTests/types/address_balance.sol index c4d10fead..375a47e94 100644 --- a/test/libsolidity/smtCheckerTests/types/address_balance.sol +++ b/test/libsolidity/smtCheckerTests/types/address_balance.sol @@ -9,5 +9,5 @@ contract C } // ---- // Warning 2072: (96-102): Unused local variable. -// Warning 4984: (105-127): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning 6328: (131-160): Assertion violation happens here +// Warning 4984: (105-127): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (131-160): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_call.sol b/test/libsolidity/smtCheckerTests/types/address_call.sol index 275f1b6cf..a8134b397 100644 --- a/test/libsolidity/smtCheckerTests/types/address_call.sol +++ b/test/libsolidity/smtCheckerTests/types/address_call.sol @@ -19,7 +19,7 @@ contract C // EVMVersion: >spuriousDragon // ---- // Warning 2072: (224-240): Unused local variable. -// Warning 6328: (260-275): Assertion violation happens here -// Warning 6328: (279-293): Assertion violation happens here -// Warning 6328: (297-316): Assertion violation happens here -// Warning 6328: (320-344): Assertion violation happens here +// Warning 6328: (260-275): CHC: Assertion violation happens here. +// Warning 6328: (279-293): CHC: Assertion violation happens here. +// Warning 6328: (297-316): CHC: Assertion violation happens here. +// Warning 6328: (320-344): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_delegatecall.sol b/test/libsolidity/smtCheckerTests/types/address_delegatecall.sol index 3dd9e07cb..b9a03a3ca 100644 --- a/test/libsolidity/smtCheckerTests/types/address_delegatecall.sol +++ b/test/libsolidity/smtCheckerTests/types/address_delegatecall.sol @@ -19,7 +19,7 @@ contract C // EVMVersion: >spuriousDragon // ---- // Warning 2072: (224-240): Unused local variable. -// Warning 6328: (268-283): Assertion violation happens here -// Warning 6328: (287-301): Assertion violation happens here -// Warning 6328: (305-324): Assertion violation happens here -// Warning 6328: (328-352): Assertion violation happens here +// Warning 6328: (268-283): CHC: Assertion violation happens here. +// Warning 6328: (287-301): CHC: Assertion violation happens here. +// Warning 6328: (305-324): CHC: Assertion violation happens here. +// Warning 6328: (328-352): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_staticcall.sol b/test/libsolidity/smtCheckerTests/types/address_staticcall.sol index 05c10febc..74cd085d2 100644 --- a/test/libsolidity/smtCheckerTests/types/address_staticcall.sol +++ b/test/libsolidity/smtCheckerTests/types/address_staticcall.sol @@ -19,4 +19,4 @@ contract C // EVMVersion: >spuriousDragon // ---- // Warning 2072: (224-240): Unused local variable. -// Warning 6328: (266-281): Assertion violation happens here +// Warning 6328: (266-281): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer.sol b/test/libsolidity/smtCheckerTests/types/address_transfer.sol index ae435cec5..3e735f5b5 100644 --- a/test/libsolidity/smtCheckerTests/types/address_transfer.sol +++ b/test/libsolidity/smtCheckerTests/types/address_transfer.sol @@ -11,5 +11,5 @@ contract C } } // ---- -// Warning 6328: (195-219): Assertion violation happens here -// Warning 1236: (131-146): Insufficient funds happens here +// Warning 6328: (195-219): CHC: Assertion violation happens here. +// Warning 1236: (131-146): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer_2.sol b/test/libsolidity/smtCheckerTests/types/address_transfer_2.sol index f6bc0ef6d..11bddf467 100644 --- a/test/libsolidity/smtCheckerTests/types/address_transfer_2.sol +++ b/test/libsolidity/smtCheckerTests/types/address_transfer_2.sol @@ -14,6 +14,6 @@ contract C } } // ---- -// Warning 6328: (295-324): Assertion violation happens here -// Warning 1236: (217-232): Insufficient funds happens here -// Warning 1236: (236-251): Insufficient funds happens here +// Warning 6328: (295-324): CHC: Assertion violation happens here. +// Warning 1236: (217-232): BMC: Insufficient funds happens here. +// Warning 1236: (236-251): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol index 8c4f37bf2..f32c86509 100644 --- a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol +++ b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol @@ -11,6 +11,6 @@ contract C } } // ---- -// Warning 6328: (213-237): Assertion violation happens here -// Warning 1236: (134-149): Insufficient funds happens here -// Warning 1236: (153-169): Insufficient funds happens here +// Warning 6328: (213-237): CHC: Assertion violation happens here. +// Warning 1236: (134-149): BMC: Insufficient funds happens here. +// Warning 1236: (153-169): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol index 6b09f780d..78d13ed14 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol @@ -26,4 +26,4 @@ contract C } } // ---- -// Warning 6328: (400-457): Assertion violation happens here +// Warning 6328: (400-457): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol index 2e46f6890..7ea15fdbd 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol @@ -16,4 +16,4 @@ contract C } } // ---- -// Warning 6328: (321-338): Assertion violation happens here +// Warning 6328: (321-338): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol index 5885053c5..e9d7a903c 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol @@ -20,4 +20,4 @@ contract C } } // ---- -// Warning 6328: (476-493): Assertion violation happens here +// Warning 6328: (476-493): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol index 75b265284..9e31d0a20 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol @@ -44,8 +44,8 @@ contract C } } // ---- -// Warning 6328: (468-485): Assertion violation happens here. -// Warning 6328: (532-554): Assertion violation happens here. -// Warning 6328: (606-633): Assertion violation happens here. -// Warning 6328: (774-796): Assertion violation happens here. -// Warning 6328: (936-962): Assertion violation happens here. +// Warning 6328: (468-485): CHC: Assertion violation happens here. +// Warning 6328: (532-554): CHC: Assertion violation happens here. +// Warning 6328: (606-633): CHC: Assertion violation happens here. +// Warning 6328: (774-796): CHC: Assertion violation happens here. +// Warning 6328: (936-962): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol index 75077c31a..f30ab1213 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol @@ -20,4 +20,4 @@ contract C } } // ---- -// Warning 6328: (436-453): Assertion violation happens here +// Warning 6328: (436-453): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol index b59f340ad..b111e959f 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol @@ -23,5 +23,5 @@ contract C } } // ---- -// Warning 6328: (524-542): Assertion violation happens here -// Warning 6328: (585-602): Assertion violation happens here +// Warning 6328: (524-542): CHC: Assertion violation happens here. +// Warning 6328: (585-602): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol index d1440dd92..2a99d1a45 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol @@ -19,5 +19,5 @@ contract C } } // ---- -// Warning 6328: (225-242): Assertion violation happens here -// Warning 6328: (289-307): Assertion violation happens here +// Warning 6328: (225-242): CHC: Assertion violation happens here. +// Warning 6328: (289-307): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol index 8f592202f..2e9f58edd 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol @@ -26,5 +26,5 @@ contract C } } // ---- -// Warning 6328: (431-449): Assertion violation happens here -// Warning 6328: (504-521): Assertion violation happens here +// Warning 6328: (431-449): CHC: Assertion violation happens here. +// Warning 6328: (504-521): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_branch_1d.sol b/test/libsolidity/smtCheckerTests/types/array_branch_1d.sol index f518188dd..19ce772d7 100644 --- a/test/libsolidity/smtCheckerTests/types/array_branch_1d.sol +++ b/test/libsolidity/smtCheckerTests/types/array_branch_1d.sol @@ -11,4 +11,4 @@ contract C } // ---- // Warning 2018: (47-148): Function state mutability can be restricted to pure -// Warning 6328: (128-144): Assertion violation happens here +// Warning 6328: (128-144): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_branch_2d.sol b/test/libsolidity/smtCheckerTests/types/array_branch_2d.sol index 1c782058f..95fee2568 100644 --- a/test/libsolidity/smtCheckerTests/types/array_branch_2d.sol +++ b/test/libsolidity/smtCheckerTests/types/array_branch_2d.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (130-149): Assertion violation happens here +// Warning 6328: (130-149): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_branch_3d.sol b/test/libsolidity/smtCheckerTests/types/array_branch_3d.sol index f46069553..3cb454014 100644 --- a/test/libsolidity/smtCheckerTests/types/array_branch_3d.sol +++ b/test/libsolidity/smtCheckerTests/types/array_branch_3d.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (138-160): Assertion violation happens here +// Warning 6328: (138-160): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_dynamic_1_fail.sol b/test/libsolidity/smtCheckerTests/types/array_dynamic_1_fail.sol index 4d0ab0b8b..809d441ce 100644 --- a/test/libsolidity/smtCheckerTests/types/array_dynamic_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_dynamic_1_fail.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (137-159): Assertion violation happens here +// Warning 6328: (137-159): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_dynamic_2_fail.sol b/test/libsolidity/smtCheckerTests/types/array_dynamic_2_fail.sol index 6111c7247..8dfc22470 100644 --- a/test/libsolidity/smtCheckerTests/types/array_dynamic_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_dynamic_2_fail.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (243-268): Assertion violation happens here +// Warning 6328: (243-268): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_dynamic_3_fail.sol b/test/libsolidity/smtCheckerTests/types/array_dynamic_3_fail.sol index 5c44924cb..525c32584 100644 --- a/test/libsolidity/smtCheckerTests/types/array_dynamic_3_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_dynamic_3_fail.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (274-302): Assertion violation happens here +// Warning 6328: (274-302): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_dynamic_parameter_1_fail.sol b/test/libsolidity/smtCheckerTests/types/array_dynamic_parameter_1_fail.sol index b49c7d5e0..01f153d67 100644 --- a/test/libsolidity/smtCheckerTests/types/array_dynamic_parameter_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_dynamic_parameter_1_fail.sol @@ -9,4 +9,4 @@ contract C } } // ---- -// Warning 6328: (148-170): Assertion violation happens here +// Warning 6328: (148-170): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol index 82508ab21..a8f5c42ec 100644 --- a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol @@ -23,5 +23,5 @@ contract C } } // ---- -// Warning 6328: (421-452): Assertion violation happens here -// Warning 6328: (635-671): Assertion violation happens here +// Warning 6328: (421-452): CHC: Assertion violation happens here. +// Warning 6328: (635-671): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol index 7fa85234f..8603a54b7 100644 --- a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol @@ -26,4 +26,4 @@ contract C } } // ---- -// Warning 6328: (777-797): Assertion violation happens here +// Warning 6328: (777-797): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_1_fail.sol b/test/libsolidity/smtCheckerTests/types/array_static_1_fail.sol index 87d385190..6a43c5801 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_1_fail.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (139-161): Assertion violation happens here +// Warning 6328: (139-161): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_2_fail.sol b/test/libsolidity/smtCheckerTests/types/array_static_2_fail.sol index 3ef862bf8..b19d9b07f 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_2_fail.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (186-211): Assertion violation happens here +// Warning 6328: (186-211): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_3_fail.sol b/test/libsolidity/smtCheckerTests/types/array_static_3_fail.sol index 2e6fc54c7..fff407a48 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_3_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_3_fail.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (280-308): Assertion violation happens here +// Warning 6328: (280-308): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol index c2b2b9ab5..ecb39847d 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol @@ -14,5 +14,5 @@ contract C } } // ---- -// Warning 6328: (228-246): Assertion violation happens here -// Warning 6328: (293-310): Assertion violation happens here +// Warning 6328: (228-246): CHC: Assertion violation happens here. +// Warning 6328: (293-310): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol index 429e5428d..068c36b11 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol @@ -21,4 +21,4 @@ contract C } } // ---- -// Warning 6328: (338-355): Assertion violation happens here +// Warning 6328: (338-355): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol index 185797d69..dd99ae130 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol @@ -23,5 +23,5 @@ contract C } } // ---- -// Warning 6328: (425-456): Assertion violation happens here -// Warning 6328: (639-675): Assertion violation happens here +// Warning 6328: (425-456): CHC: Assertion violation happens here. +// Warning 6328: (639-675): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol index c9ed4f34c..f27c21fb4 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol @@ -26,4 +26,4 @@ contract C } } // ---- -// Warning 6328: (781-801): Assertion violation happens here +// Warning 6328: (781-801): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/array_struct_array_branches_2d.sol b/test/libsolidity/smtCheckerTests/types/array_struct_array_branches_2d.sol index f7cb6f957..a4531079b 100644 --- a/test/libsolidity/smtCheckerTests/types/array_struct_array_branches_2d.sol +++ b/test/libsolidity/smtCheckerTests/types/array_struct_array_branches_2d.sol @@ -14,19 +14,3 @@ contract C } } // ---- -// Warning 6328: (202-226): Assertion violation happens here -// Warning 7650: (124-130): Assertion checker does not yet support this expression. -// Warning 8364: (124-128): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (124-133): Assertion checker does not yet implement this expression. -// Warning 9056: (124-136): Assertion checker does not yet implement this expression. -// Warning 7650: (154-160): Assertion checker does not yet support this expression. -// Warning 8364: (154-158): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (154-163): Assertion checker does not yet implement this expression. -// Warning 9056: (154-166): Assertion checker does not yet implement this expression. -// Warning 7650: (182-188): Assertion checker does not yet support this expression. -// Warning 8364: (182-186): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (182-191): Assertion checker does not yet implement this expression. -// Warning 9056: (182-194): Assertion checker does not yet implement this expression. -// Warning 7650: (209-215): Assertion checker does not yet support this expression. -// Warning 8364: (209-213): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (209-218): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol index f499d14fd..2716acd28 100644 --- a/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// Warning 6328: (90-99): Assertion violation happens here +// Warning 6328: (90-99): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol index 9905ca0ba..0632acc6c 100644 --- a/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// Warning 6328: (98-112): Assertion violation happens here +// Warning 6328: (98-112): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/bytes_2_fail.sol b/test/libsolidity/smtCheckerTests/types/bytes_2_fail.sol index 433125a63..b32d21d22 100644 --- a/test/libsolidity/smtCheckerTests/types/bytes_2_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/bytes_2_fail.sol @@ -8,4 +8,4 @@ contract C } } // ---- -// Warning 6328: (119-141): Assertion violation happens here +// Warning 6328: (119-141): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/bytes_length.sol b/test/libsolidity/smtCheckerTests/types/bytes_length.sol new file mode 100644 index 000000000..e248165af --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bytes_length.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + bytes memory x = hex"0123"; + assert(x.length == 2); + } + function g() public pure { + bytes memory x = bytes(hex"0123"); + assert(x.length == 2); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/types/contract.sol b/test/libsolidity/smtCheckerTests/types/contract.sol index aca1a4613..bd6b33698 100644 --- a/test/libsolidity/smtCheckerTests/types/contract.sol +++ b/test/libsolidity/smtCheckerTests/types/contract.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (84-98): Assertion violation happens here +// Warning 6328: (84-98): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/contract_2.sol b/test/libsolidity/smtCheckerTests/types/contract_2.sol index 8d79761e5..8667576b9 100644 --- a/test/libsolidity/smtCheckerTests/types/contract_2.sol +++ b/test/libsolidity/smtCheckerTests/types/contract_2.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (109-123): Assertion violation happens here +// Warning 6328: (109-123): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/contract_address_conversion.sol b/test/libsolidity/smtCheckerTests/types/contract_address_conversion.sol index ae1e407b7..33fb94240 100644 --- a/test/libsolidity/smtCheckerTests/types/contract_address_conversion.sol +++ b/test/libsolidity/smtCheckerTests/types/contract_address_conversion.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (90-113): Assertion violation happens here +// Warning 6328: (90-113): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/enum_explicit_values_2.sol b/test/libsolidity/smtCheckerTests/types/enum_explicit_values_2.sol index 787cb2807..a4ed90219 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_explicit_values_2.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_explicit_values_2.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (144-159): Assertion violation happens here +// Warning 6328: (144-159): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol b/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol index 7e54307ed..17b54c364 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (159-179): Assertion violation happens here +// Warning 6328: (159-179): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol b/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol index 8c8636e59..ffe5dfd95 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol @@ -11,10 +11,3 @@ contract C } } // ---- -// Warning 6328: (187-208): Assertion violation happens here -// Warning 8115: (143-153): Assertion checker does not yet support the type of this variable. -// Warning 7650: (171-174): Assertion checker does not yet support this expression. -// Warning 8364: (171-172): Assertion checker does not yet implement type struct C.S memory -// Warning 8182: (171-183): Assertion checker does not yet implement such assignments. -// Warning 7650: (194-197): Assertion checker does not yet support this expression. -// Warning 8364: (194-195): Assertion checker does not yet implement type struct C.S memory diff --git a/test/libsolidity/smtCheckerTests/types/enum_storage_eq.sol b/test/libsolidity/smtCheckerTests/types/enum_storage_eq.sol index e43404600..42c10f513 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_storage_eq.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_storage_eq.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (115-130): Assertion violation happens here +// Warning 6328: (115-130): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_1.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_1.sol index 55138482c..a75a5478b 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_1.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_1.sol @@ -12,5 +12,5 @@ contract C } } // ---- -// Warning 6328: (96-110): Assertion violation happens here -// Warning 6328: (114-130): Assertion violation happens here +// Warning 6328: (96-110): CHC: Assertion violation happens here. +// Warning 6328: (114-130): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol index 46409c1e6..40f4c1bdb 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol @@ -12,4 +12,4 @@ contract C } } // ---- -// Warning 6328: (116-130): Assertion violation happens here +// Warning 6328: (116-130): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_1.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_1.sol index 636dd7ff1..76e8c2ead 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_1.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_1.sol @@ -6,4 +6,3 @@ contract c { } } // ---- -// Warning 7989: (123-134): Assertion checker does not yet support index accessing fixed bytes. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_2.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_2.sol index e81d093f8..ea645ccaf 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_2.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_2.sol @@ -6,6 +6,4 @@ contract C { } } // ---- -// Warning 7989: (101-108): Assertion checker does not yet support index accessing fixed bytes. -// Warning 7989: (112-121): Assertion checker does not yet support index accessing fixed bytes. -// Warning 3046: (117-120): Division by zero happens here +// Warning 3046: (117-120): BMC: Division by zero happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_3.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_3.sol index 5348ca1b4..a85802993 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_3.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_3.sol @@ -13,6 +13,3 @@ contract C { } } // ---- -// Warning 9118: (238-244): Assertion checker does not yet implement this expression. -// Warning 7989: (238-247): Assertion checker does not yet support index accessing fixed bytes. -// Warning 7989: (251-257): Assertion checker does not yet support index accessing fixed bytes. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol new file mode 100644 index 000000000..55fa57136 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol @@ -0,0 +1,15 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + bytes32 x = 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff; + byte z = 0x00; + byte o = 0xff; + assert(x[0] == z); + assert(x[31] == o); + assert(x[0] == x[22]); + assert(x[0] == x[23]); + } +} +// ---- +// Warning 6328: (260-281): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol new file mode 100644 index 000000000..595072a75 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + bytes4 x = 0x01020304; + byte b = 0x02; + assert(x[0] == b); // fails + assert(x[1] == b); + assert(x[2] == b); // fails + assert(x[3] == b); // fails + } +} +// ---- +// Warning 6328: (118-135): CHC: Assertion violation happens here. +// Warning 6328: (169-186): CHC: Assertion violation happens here. +// Warning 6328: (199-216): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_6.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_6.sol new file mode 100644 index 000000000..8332d8117 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_6.sol @@ -0,0 +1,11 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + bytes4 x = 0x01020304; + byte b = x[3]; + assert(b == b[0]); + assert(b == b[0][0]); + assert(b == b[0][0][0][0][0][0][0][0][0][0][0]); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol new file mode 100644 index 000000000..6ddff6088 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint i) public pure { + bytes4 x = 0x01020304; + require(i > 3); + assert(x[i] == 0x00); + i = 5; + assert(x[i] == 0); + assert(x[i] != 0); + } +} +// ---- +// Warning 6328: (125-145): CHC: Assertion violation happens here. +// Warning 6328: (158-175): CHC: Assertion violation happens here. +// Warning 6328: (179-196): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/function_in_tuple_1.sol b/test/libsolidity/smtCheckerTests/types/function_in_tuple_1.sol index 40b0c0b7a..1a41149e9 100644 --- a/test/libsolidity/smtCheckerTests/types/function_in_tuple_1.sol +++ b/test/libsolidity/smtCheckerTests/types/function_in_tuple_1.sol @@ -7,4 +7,3 @@ contract K { } // ---- // Warning 6133: (76-91): Statement has no effect. -// Warning 8364: (77-80): Assertion checker does not yet implement type abi diff --git a/test/libsolidity/smtCheckerTests/types/function_in_tuple_2.sol b/test/libsolidity/smtCheckerTests/types/function_in_tuple_2.sol index cecb9f967..f64311922 100644 --- a/test/libsolidity/smtCheckerTests/types/function_in_tuple_2.sol +++ b/test/libsolidity/smtCheckerTests/types/function_in_tuple_2.sol @@ -7,4 +7,3 @@ contract K { } // ---- // Warning 6133: (76-92): Statement has no effect. -// Warning 8364: (77-80): Assertion checker does not yet implement type abi diff --git a/test/libsolidity/smtCheckerTests/types/function_type_arrays.sol b/test/libsolidity/smtCheckerTests/types/function_type_arrays.sol index e2810721b..a0ebf4379 100644 --- a/test/libsolidity/smtCheckerTests/types/function_type_arrays.sol +++ b/test/libsolidity/smtCheckerTests/types/function_type_arrays.sol @@ -7,8 +7,8 @@ contract C { function(uint) returns (uint)[10] storage b = y; function(uint) external returns (uint)[] memory c; c = new function(uint) external returns (uint)[](200); + assert(c.length == 200); a; b; } } // ---- -// Warning 4588: (361-410): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol b/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol index 549701105..c7b405c50 100644 --- a/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol +++ b/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol @@ -7,4 +7,4 @@ contract C { } // ---- // Warning 7650: (128-137): Assertion checker does not yet support this expression. -// Warning 4661: (141-155): Assertion violation happens here +// Warning 4661: (141-155): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_1_fail.sol b/test/libsolidity/smtCheckerTests/types/mapping_1_fail.sol index 079e1eded..fa0dabd9f 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_1_fail.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (134-153): Assertion violation happens here +// Warning 6328: (134-153): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_2.sol b/test/libsolidity/smtCheckerTests/types/mapping_2.sol index b8e9ebe5b..b664d5ffd 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_2.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_2.sol @@ -8,4 +8,4 @@ contract C } } // ---- -// Warning 6328: (111-130): Assertion violation happens here +// Warning 6328: (111-130): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_2d_1_fail.sol b/test/libsolidity/smtCheckerTests/types/mapping_2d_1_fail.sol index 2156b469e..7effc7bb5 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_2d_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_2d_1_fail.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (154-178): Assertion violation happens here +// Warning 6328: (154-178): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_3d_1_fail.sol b/test/libsolidity/smtCheckerTests/types/mapping_3d_1_fail.sol index 9792df905..71f0c5d4c 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_3d_1_fail.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_3d_1_fail.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (176-204): Assertion violation happens here +// Warning 6328: (176-204): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_5.sol b/test/libsolidity/smtCheckerTests/types/mapping_5.sol index 6ebdf518b..60b26b50a 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_5.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_5.sol @@ -8,4 +8,4 @@ contract C } } // ---- -// Warning 6328: (125-144): Assertion violation happens here +// Warning 6328: (125-144): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol index afe1ce6dc..c747508d5 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol @@ -16,4 +16,4 @@ contract C } } // ---- -// Warning 6328: (266-286): Assertion violation happens here +// Warning 6328: (266-286): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol new file mode 100644 index 000000000..206586117 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol @@ -0,0 +1,35 @@ +pragma experimental SMTChecker; + +contract C +{ + mapping (uint => uint) a; + mapping (uint => mapping (uint => uint)) maps; + mapping (uint => mapping (uint => uint8)) maps8; + function f(mapping (uint => uint) storage map1, mapping (uint => uint) storage map2) internal { + map1[0] = 2; + a[0] = 42; + maps[0][0] = 42; + maps8[0][0] = 42; + map2[0] = 1; + // Fails because map2 == map1 is possible. + assert(map1[0] == 2); + // Fails because map2 == a is possible. + assert(a[0] == 42); + // Fails because map2 == maps[0] is possible. + assert(maps[0][0] == 42); + // Should not fail since knowledge is erased only for mapping (uint => uint). + assert(maps8[0][0] == 42); + assert(map2[0] == 1); + } + + function g(bool b, uint x, uint y) public { + if (b) + f(a, maps[y]); + else + f(maps[x], maps[y]); + } +} +// ---- +// Warning 6328: (397-417): CHC: Assertion violation happens here. +// Warning 6328: (463-481): CHC: Assertion violation happens here. +// Warning 6328: (533-557): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_as_local_var_1.sol b/test/libsolidity/smtCheckerTests/types/mapping_as_local_var_1.sol index e99eea071..c256ace86 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_as_local_var_1.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_as_local_var_1.sol @@ -16,5 +16,5 @@ contract c { } } // ---- -// Warning 6328: (288-324): Assertion violation happens here -// Warning 6328: (336-372): Assertion violation happens here +// Warning 6328: (288-324): CHC: Assertion violation happens here. +// Warning 6328: (336-372): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_as_parameter_1.sol b/test/libsolidity/smtCheckerTests/types/mapping_as_parameter_1.sol index cd2f34168..79c37029e 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_as_parameter_1.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_as_parameter_1.sol @@ -12,4 +12,4 @@ contract c { } } // ---- -// Warning 6328: (289-306): Assertion violation happens here +// Warning 6328: (289-306): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol b/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol index f77baadef..6ed23ca39 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol @@ -9,4 +9,4 @@ contract C } } // ---- -// Warning 6328: (119-133): Assertion violation happens here +// Warning 6328: (119-133): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_struct_assignment.sol b/test/libsolidity/smtCheckerTests/types/mapping_struct_assignment.sol index ec9ca8145..fa2c2d10d 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_struct_assignment.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_struct_assignment.sol @@ -11,9 +11,6 @@ contract C } } // ---- -// Warning 6838: (140-144): Condition is always false. -// Warning 8364: (149-156): Assertion checker does not yet implement type struct C.S storage ref +// Warning 6838: (140-144): BMC: Condition is always false. // Warning 8364: (159-160): Assertion checker does not yet implement type type(struct C.S storage pointer) -// Warning 8364: (159-163): Assertion checker does not yet implement type struct C.S memory // Warning 4639: (159-163): Assertion checker does not yet implement this expression. -// Warning 8364: (149-163): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/types/no_effect_statements.sol b/test/libsolidity/smtCheckerTests/types/no_effect_statements.sol index 761b401c2..d97d33cbe 100644 --- a/test/libsolidity/smtCheckerTests/types/no_effect_statements.sol +++ b/test/libsolidity/smtCheckerTests/types/no_effect_statements.sol @@ -17,7 +17,6 @@ contract test { // Warning 6133: (156-163): Statement has no effect. // Warning 8364: (125-126): Assertion checker does not yet implement type type(struct test.s storage pointer) // Warning 8364: (130-131): Assertion checker does not yet implement type type(struct test.s storage pointer) -// Warning 8364: (130-136): Assertion checker does not yet implement type struct test.s memory // Warning 4639: (130-136): Assertion checker does not yet implement this expression. // Warning 8364: (140-141): Assertion checker does not yet implement type type(struct test.s storage pointer) // Warning 8364: (140-144): Assertion checker does not yet implement type type(struct test.s memory[7] memory) diff --git a/test/libsolidity/smtCheckerTests/types/rational_large_1.sol b/test/libsolidity/smtCheckerTests/types/rational_large_1.sol index 5353ed6f8..a6b74520b 100644 --- a/test/libsolidity/smtCheckerTests/types/rational_large_1.sol +++ b/test/libsolidity/smtCheckerTests/types/rational_large_1.sol @@ -7,4 +7,4 @@ contract c { } } // ---- -// Warning 6328: (128-142): Assertion violation happens here +// Warning 6328: (128-142): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol index 4bb6409ca..46dadd813 100644 --- a/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol @@ -19,4 +19,4 @@ contract C } } // ---- -// Warning 6328: (362-421): Assertion violation happens here +// Warning 6328: (362-421): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol index f18a466b1..ecb500698 100644 --- a/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol @@ -9,4 +9,4 @@ contract C } } // ---- -// Warning 6328: (123-136): Assertion violation happens here +// Warning 6328: (123-136): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol index 776c2541c..a9aac3b33 100644 --- a/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol @@ -7,4 +7,4 @@ contract C uint c; } // ---- -// Warning 6328: (84-97): Assertion violation happens here +// Warning 6328: (84-97): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_1.sol b/test/libsolidity/smtCheckerTests/types/string_1.sol index 19a7fa094..f5c6d48db 100644 --- a/test/libsolidity/smtCheckerTests/types/string_1.sol +++ b/test/libsolidity/smtCheckerTests/types/string_1.sol @@ -7,4 +7,4 @@ contract C } } // ---- -// Warning 6328: (110-154): Assertion violation happens here +// Warning 6328: (110-154): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_length.sol b/test/libsolidity/smtCheckerTests/types/string_length.sol new file mode 100644 index 000000000..632eada19 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/string_length.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; + +contract C { + function f() public pure { + string memory x = "Hello World"; + assert(bytes(x).length == 11); + } + function g() public pure { + string memory x = unicode"Hello World"; + assert(bytes(x).length == 11); + } + function h() public pure { + bytes memory x = unicode"Hello World"; + string memory y = string(x); + assert(bytes(y).length == 11); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol index 834cce276..b6020c7f7 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol @@ -10,4 +10,4 @@ contract C { } } // ---- -// Warning 6328: (175-190): Assertion violation happens here +// Warning 6328: (175-190): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol index c2b74b2fe..8a5578a56 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 6328: (176-191): Assertion violation happens here +// Warning 6328: (176-191): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol index 3fe3bf2d1..5a1212a34 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 6328: (186-201): Assertion violation happens here +// Warning 6328: (186-201): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol index f72e6386f..5add77d6a 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol @@ -15,4 +15,4 @@ contract C { } } // ---- -// Warning 6328: (261-276): Assertion violation happens here +// Warning 6328: (261-276): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol index ee4994913..d0ed3711b 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol @@ -13,4 +13,4 @@ contract C { } } // ---- -// Warning 6328: (251-266): Assertion violation happens here +// Warning 6328: (251-266): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol index 92f3c7e41..aba732c35 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol @@ -10,4 +10,4 @@ contract C { } } // ---- -// Warning 6328: (170-190): Assertion violation happens here +// Warning 6328: (170-190): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol index 28f296add..7f342f47e 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol @@ -10,5 +10,5 @@ contract C { } } // ---- -// Warning 6328: (147-166): Assertion violation happens here -// Warning 6328: (170-190): Assertion violation happens here +// Warning 6328: (147-166): CHC: Assertion violation happens here. +// Warning 6328: (170-190): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_memory_safe.sol b/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_memory_safe.sol new file mode 100644 index 000000000..c7524fb64 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_memory_safe.sol @@ -0,0 +1,30 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + function f() public pure { + S[] memory s1 = new S[](3); + assert(s1.length == 3); + s1[0].x = 2; + assert(s1[0].x == 2); + s1[1].t.y = 3; + assert(s1[1].t.y == 3); + s1[2].a[2] = 4; + assert(s1[2].a[2] == 4); + s1[0].ts[3].y = 5; + assert(s1[0].ts[3].y == 5); + s1[1].ts[4].a[5] = 6; + assert(s1[1].ts[4].a[5] == 6); + } +} +// ---- diff --git a/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_memory_unsafe.sol b/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_memory_unsafe.sol new file mode 100644 index 000000000..6ade5f038 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_memory_unsafe.sol @@ -0,0 +1,35 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + function f(S memory s2) public pure { + S[] memory s1 = new S[](3); + assert(s1.length == 3); + s1[0].x = 2; + assert(s1[0].x == s2.x); + s1[1].t.y = 3; + assert(s1[1].t.y == s2.t.y); + s1[2].a[2] = 4; + assert(s1[2].a[2] == s2.a[2]); + s1[0].ts[3].y = 5; + assert(s1[0].ts[3].y == s2.ts[3].y); + s1[1].ts[4].a[5] = 6; + assert(s1[1].ts[4].a[5] == s2.ts[4].a[5]); + } +} +// ---- +// Warning 6328: (283-306): CHC: Assertion violation happens here. +// Warning 6328: (327-354): CHC: Assertion violation happens here. +// Warning 6328: (376-405): CHC: Assertion violation happens here. +// Warning 6328: (430-465): CHC: Assertion violation happens here. +// Warning 6328: (493-534): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_storage_safe.sol b/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_storage_safe.sol new file mode 100644 index 000000000..bfa45c90f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/array_struct_array_struct_storage_safe.sol @@ -0,0 +1,34 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + S[] s1; + function f() public { + s1.push(); + s1.push(); + s1.push(); + s1[0].x = 2; + assert(s1[0].x == 2); + s1[1].t.y = 3; + assert(s1[1].t.y == 3); + s1[2].a[2] = 4; + assert(s1[2].a[2] == 4); + s1[0].ts[3].y = 5; + assert(s1[0].ts[3].y == 5); + s1[1].ts[4].a[5] = 6; + assert(s1[1].ts[4].a[5] == 6); + s1.pop(); + s1.pop(); + s1.pop(); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_memory.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_memory.sol new file mode 100644 index 000000000..a6be72cc4 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_memory.sol @@ -0,0 +1,23 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint x; + uint[] a; + } + function f(S memory s1, S memory s2, bool b) public pure { + S memory s3 = b ? s1 : s2; + assert(s3.x == s1.x); + assert(s3.x == s2.x); + // This is safe. + assert(s3.x == s1.x || s3.x == s2.x); + // This fails as false positive because of lack of support to aliasing. + s3.x = 42; + assert(s3.x == s1.x || s3.x == s2.x); + } +} +// ---- +// Warning 6328: (208-228): CHC: Assertion violation happens here. +// Warning 6328: (232-252): CHC: Assertion violation happens here. +// Warning 6328: (402-438): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_storage.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_storage.sol new file mode 100644 index 000000000..a8e48fc09 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_storage.sol @@ -0,0 +1,30 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + uint[] a; + } + S s1; + S s2; + function f(bool b) public { + S storage s3 = b ? s1 : s2; + assert(s3.x == s1.x); + assert(s3.x == s2.x); + // This is safe. + assert(s3.x == s1.x || s3.x == s2.x); + // This fails as false positive because of lack of support to aliasing. + s3.x = 42; + assert(s3.x == s1.x || s3.x == s2.x); + } + function g(bool b, uint _x) public { + if (b) + s1.x = _x; + else + s2.x = _x; + } +} +// ---- +// Warning 6328: (158-178): CHC: Assertion violation happens here. +// Warning 6328: (182-202): CHC: Assertion violation happens here. +// Warning 6328: (352-388): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_safe.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_safe.sol new file mode 100644 index 000000000..ed8d97905 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_safe.sol @@ -0,0 +1,28 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + function f() public pure { + S memory s1; + s1.x = 2; + assert(s1.x == 2); + s1.t.y = 3; + assert(s1.t.y == 3); + s1.a[2] = 4; + assert(s1.a[2] == 4); + s1.ts[3].y = 5; + assert(s1.ts[3].y == 5); + s1.ts[4].a[5] = 6; + assert(s1.ts[4].a[5] == 6); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_unsafe_1.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_unsafe_1.sol new file mode 100644 index 000000000..dcdad4da7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_unsafe_1.sol @@ -0,0 +1,34 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + function f() public pure { + S memory s1; + s1.x = 2; + assert(s1.x != 2); + s1.t.y = 3; + assert(s1.t.y != 3); + s1.a[2] = 4; + assert(s1.a[2] != 4); + s1.ts[3].y = 5; + assert(s1.ts[3].y != 5); + s1.ts[4].a[5] = 6; + assert(s1.ts[4].a[5] != 6); + } +} +// ---- +// Warning 6328: (228-245): CHC: Assertion violation happens here. +// Warning 6328: (263-282): CHC: Assertion violation happens here. +// Warning 6328: (301-321): CHC: Assertion violation happens here. +// Warning 6328: (343-366): CHC: Assertion violation happens here. +// Warning 6328: (391-417): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_unsafe_2.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_unsafe_2.sol new file mode 100644 index 000000000..2a7c42228 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_memory_unsafe_2.sol @@ -0,0 +1,34 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + function f(S memory s2) public pure { + S memory s1; + s1.x = 2; + assert(s1.x == s2.x); + s1.t.y = 3; + assert(s1.t.y == s2.t.y); + s1.a[2] = 4; + assert(s1.a[2] == s2.a[2]); + s1.ts[3].y = 5; + assert(s1.ts[3].y == s2.ts[3].y); + s1.ts[4].a[5] = 6; + assert(s1.ts[4].a[5] == s2.ts[4].a[5]); + } +} +// ---- +// Warning 6328: (239-259): CHC: Assertion violation happens here. +// Warning 6328: (277-301): CHC: Assertion violation happens here. +// Warning 6328: (320-346): CHC: Assertion violation happens here. +// Warning 6328: (368-400): CHC: Assertion violation happens here. +// Warning 6328: (425-463): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_storage_safe.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_storage_safe.sol new file mode 100644 index 000000000..4240f6267 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_storage_safe.sol @@ -0,0 +1,27 @@ +pragma experimental SMTChecker; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + S s1; + function f() public { + s1.x = 2; + assert(s1.x == 2); + s1.t.y = 3; + assert(s1.t.y == 3); + s1.a[2] = 4; + assert(s1.a[2] == 4); + s1.ts[3].y = 5; + assert(s1.ts[3].y == 5); + s1.ts[4].a[5] = 6; + assert(s1.ts[4].a[5] == 6); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_storage_unsafe_1.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_storage_unsafe_1.sol new file mode 100644 index 000000000..181465423 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_array_struct_array_storage_unsafe_1.sol @@ -0,0 +1,33 @@ +pragma experimental SMTChecker; + +contract C { + struct T { + uint y; + uint[] a; + } + struct S { + uint x; + T t; + uint[] a; + T[] ts; + } + S s1; + function f() public { + s1.x = 2; + assert(s1.x != 2); + s1.t.y = 3; + assert(s1.t.y != 3); + s1.a[2] = 4; + assert(s1.a[2] != 4); + s1.ts[3].y = 5; + assert(s1.ts[3].y != 5); + s1.ts[4].a[5] = 6; + assert(s1.ts[4].a[5] != 6); + } +} +// ---- +// Warning 6328: (181-198): CHC: Assertion violation happens here. +// Warning 6328: (216-235): CHC: Assertion violation happens here. +// Warning 6328: (254-274): CHC: Assertion violation happens here. +// Warning 6328: (296-319): CHC: Assertion violation happens here. +// Warning 6328: (344-370): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_delete_memory.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_delete_memory.sol new file mode 100644 index 000000000..94c919f8b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_delete_memory.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint x; + uint[] a; + } + function f(S memory s1, S memory s2) public pure { + delete s1; + assert(s1.x == s2.x); + assert(s1.a.length == s2.a.length); + assert(s1.a.length == 0); + } +} +// ---- +// Warning 6328: (184-204): CHC: Assertion violation happens here. +// Warning 6328: (208-242): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_delete_storage.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_delete_storage.sol new file mode 100644 index 000000000..47f46767c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_delete_storage.sol @@ -0,0 +1,23 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint x; + uint[] a; + } + S s1; + function g(S memory s2) public { + s1.x = s2.x; + s1.a = s2.a; + } + function f(S memory s2) public { + delete s1; + assert(s1.x == s2.x); + assert(s1.a.length == s2.a.length); + assert(s1.a.length == 0); + } +} +// ---- +// Warning 6328: (240-260): CHC: Assertion violation happens here. +// Warning 6328: (264-298): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_mapping.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_mapping.sol new file mode 100644 index 000000000..557d649d4 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_mapping.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + mapping (uint => uint) m; + } + S s1; + S s2; + function f() public view { + assert(s1.m[0] == s2.m[0]); + } + function g(uint a, uint b) public { + s1.m[a] = b; + } +} +// ---- +// Warning 6328: (143-169): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_1.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_1.sol new file mode 100644 index 000000000..a9fe81ba1 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_1.sol @@ -0,0 +1,27 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + S[] a; + } + S s1; + S s2; + function f() public view { + assert(s1.x == s2.x); + assert(s1.a.length == s2.a.length); + } +} +// ---- +// Warning 6328: (124-144): CHC: Assertion violation happens here. +// Warning 6328: (148-182): CHC: Assertion violation happens here. +// Warning 8115: (81-85): Assertion checker does not yet support the type of this variable. +// Warning 8115: (88-92): Assertion checker does not yet support the type of this variable. +// Warning 7650: (131-135): Assertion checker does not yet support this expression. +// Warning 8364: (131-133): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (139-143): Assertion checker does not yet support this expression. +// Warning 8364: (139-141): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (155-159): Assertion checker does not yet support this expression. +// Warning 8364: (155-157): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (170-174): Assertion checker does not yet support this expression. +// Warning 8364: (170-172): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_2.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_2.sol new file mode 100644 index 000000000..56b117415 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_2.sol @@ -0,0 +1,69 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + S[] a; + } + S s1; + S s2; + function f() public view { + assert(s1.x == s2.x); + assert(s1.a.length == s2.a.length); + assert(s1.a[0].x == s2.a[0].x); + } + function g() public { + s1.x = 42; + s2.x = 42; + s1.a.push(); + s2.a.push(); + s1.a[0].x = 43; + s2.a[0].x = 43; + } +} +// ---- +// Warning 6328: (124-144): CHC: Assertion violation happens here. +// Warning 6328: (148-182): CHC: Assertion violation happens here. +// Warning 6328: (186-216): CHC: Assertion violation happens here. +// Warning 8115: (81-85): Assertion checker does not yet support the type of this variable. +// Warning 8115: (88-92): Assertion checker does not yet support the type of this variable. +// Warning 7650: (131-135): Assertion checker does not yet support this expression. +// Warning 8364: (131-133): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (139-143): Assertion checker does not yet support this expression. +// Warning 8364: (139-141): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (155-159): Assertion checker does not yet support this expression. +// Warning 8364: (155-157): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (170-174): Assertion checker does not yet support this expression. +// Warning 8364: (170-172): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (193-202): Assertion checker does not yet support this expression. +// Warning 7650: (193-197): Assertion checker does not yet support this expression. +// Warning 8364: (193-195): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (193-200): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (206-215): Assertion checker does not yet support this expression. +// Warning 7650: (206-210): Assertion checker does not yet support this expression. +// Warning 8364: (206-208): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (206-213): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (246-250): Assertion checker does not yet support this expression. +// Warning 8364: (246-248): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (246-250): Assertion checker does not support recursive structs. +// Warning 7650: (259-263): Assertion checker does not yet support this expression. +// Warning 8364: (259-261): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (259-263): Assertion checker does not support recursive structs. +// Warning 7650: (272-276): Assertion checker does not yet support this expression. +// Warning 8364: (272-274): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (272-283): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (272-276): Assertion checker does not support recursive structs. +// Warning 7650: (287-291): Assertion checker does not yet support this expression. +// Warning 8364: (287-289): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (287-298): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (287-291): Assertion checker does not support recursive structs. +// Warning 7650: (302-311): Assertion checker does not yet support this expression. +// Warning 7650: (302-306): Assertion checker does not yet support this expression. +// Warning 8364: (302-304): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (302-309): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (302-311): Assertion checker does not support recursive structs. +// Warning 7650: (320-329): Assertion checker does not yet support this expression. +// Warning 7650: (320-324): Assertion checker does not yet support this expression. +// Warning 8364: (320-322): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (320-327): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (320-329): Assertion checker does not support recursive structs. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_3.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_3.sol new file mode 100644 index 000000000..cbb608dec --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_3.sol @@ -0,0 +1,123 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + S[] a; + } + S s1; + S s2; + function f() public view { + assert(s1.x == s2.x); + assert(s1.a.length == s2.a.length); + assert(s1.a[0].x == s2.a[0].x); + assert(s1.a[0].a.length == s2.a[0].a.length); + assert(s1.a[0].a[0].x == s2.a[0].a[0].x); + } + function g() public { + s1.x = 42; + s2.x = 42; + s1.a.push(); + s2.a.push(); + s1.a[0].x = 43; + s2.a[0].x = 43; + s1.a[0].a.push(); + s2.a[0].a.push(); + s1.a[0].a[0].x = 44; + s2.a[0].a[0].x = 44; + } +} +// ---- +// Warning 6328: (124-144): CHC: Assertion violation happens here. +// Warning 6328: (148-182): CHC: Assertion violation happens here. +// Warning 6328: (186-216): CHC: Assertion violation happens here. +// Warning 6328: (220-264): CHC: Assertion violation happens here. +// Warning 6328: (268-308): CHC: Assertion violation happens here. +// Warning 8115: (81-85): Assertion checker does not yet support the type of this variable. +// Warning 8115: (88-92): Assertion checker does not yet support the type of this variable. +// Warning 7650: (131-135): Assertion checker does not yet support this expression. +// Warning 8364: (131-133): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (139-143): Assertion checker does not yet support this expression. +// Warning 8364: (139-141): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (155-159): Assertion checker does not yet support this expression. +// Warning 8364: (155-157): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (170-174): Assertion checker does not yet support this expression. +// Warning 8364: (170-172): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (193-202): Assertion checker does not yet support this expression. +// Warning 7650: (193-197): Assertion checker does not yet support this expression. +// Warning 8364: (193-195): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (193-200): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (206-215): Assertion checker does not yet support this expression. +// Warning 7650: (206-210): Assertion checker does not yet support this expression. +// Warning 8364: (206-208): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (206-213): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (227-236): Assertion checker does not yet support this expression. +// Warning 7650: (227-231): Assertion checker does not yet support this expression. +// Warning 8364: (227-229): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (227-234): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (247-256): Assertion checker does not yet support this expression. +// Warning 7650: (247-251): Assertion checker does not yet support this expression. +// Warning 8364: (247-249): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (247-254): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (275-289): Assertion checker does not yet support this expression. +// Warning 7650: (275-284): Assertion checker does not yet support this expression. +// Warning 7650: (275-279): Assertion checker does not yet support this expression. +// Warning 8364: (275-277): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (275-282): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (275-287): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (293-307): Assertion checker does not yet support this expression. +// Warning 7650: (293-302): Assertion checker does not yet support this expression. +// Warning 7650: (293-297): Assertion checker does not yet support this expression. +// Warning 8364: (293-295): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (293-300): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (293-305): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (338-342): Assertion checker does not yet support this expression. +// Warning 8364: (338-340): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (338-342): Assertion checker does not support recursive structs. +// Warning 7650: (351-355): Assertion checker does not yet support this expression. +// Warning 8364: (351-353): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (351-355): Assertion checker does not support recursive structs. +// Warning 7650: (364-368): Assertion checker does not yet support this expression. +// Warning 8364: (364-366): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (364-375): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (364-368): Assertion checker does not support recursive structs. +// Warning 7650: (379-383): Assertion checker does not yet support this expression. +// Warning 8364: (379-381): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (379-390): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (379-383): Assertion checker does not support recursive structs. +// Warning 7650: (394-403): Assertion checker does not yet support this expression. +// Warning 7650: (394-398): Assertion checker does not yet support this expression. +// Warning 8364: (394-396): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (394-401): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (394-403): Assertion checker does not support recursive structs. +// Warning 7650: (412-421): Assertion checker does not yet support this expression. +// Warning 7650: (412-416): Assertion checker does not yet support this expression. +// Warning 8364: (412-414): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (412-419): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (412-421): Assertion checker does not support recursive structs. +// Warning 7650: (430-439): Assertion checker does not yet support this expression. +// Warning 7650: (430-434): Assertion checker does not yet support this expression. +// Warning 8364: (430-432): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (430-437): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (430-446): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (430-439): Assertion checker does not support recursive structs. +// Warning 7650: (450-459): Assertion checker does not yet support this expression. +// Warning 7650: (450-454): Assertion checker does not yet support this expression. +// Warning 8364: (450-452): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (450-457): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (450-466): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (450-459): Assertion checker does not support recursive structs. +// Warning 7650: (470-484): Assertion checker does not yet support this expression. +// Warning 7650: (470-479): Assertion checker does not yet support this expression. +// Warning 7650: (470-474): Assertion checker does not yet support this expression. +// Warning 8364: (470-472): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (470-477): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (470-482): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (470-484): Assertion checker does not support recursive structs. +// Warning 7650: (493-507): Assertion checker does not yet support this expression. +// Warning 7650: (493-502): Assertion checker does not yet support this expression. +// Warning 7650: (493-497): Assertion checker does not yet support this expression. +// Warning 8364: (493-495): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (493-500): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (493-505): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (493-507): Assertion checker does not support recursive structs. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_4.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_4.sol new file mode 100644 index 000000000..18ec01049 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_4.sol @@ -0,0 +1,56 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + S[] a; + } + S s1; + S s2; + function f(bool b1, bool b2) public { + S storage s3 = b1 ? s1 : s2; + S storage s4 = b2 ? s1 : s2; + assert(s3.x == s1.x || s3.x == s2.x); + assert(s4.x == s1.x || s4.x == s2.x); + s3.x = 44; + // Fails as false positive because of lack of support to aliasing. + assert(s1.x == 44 || s2.x == 44); + } +} +// ---- +// Warning 6328: (197-233): CHC: Assertion violation happens here. +// Warning 6328: (237-273): CHC: Assertion violation happens here. +// Warning 6328: (359-391): CHC: Assertion violation happens here. +// Warning 8115: (81-85): Assertion checker does not yet support the type of this variable. +// Warning 8115: (88-92): Assertion checker does not yet support the type of this variable. +// Warning 8115: (135-147): Assertion checker does not yet support the type of this variable. +// Warning 8115: (166-178): Assertion checker does not yet support the type of this variable. +// Warning 8364: (155-157): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (160-162): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (150-162): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 8364: (186-188): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (191-193): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (181-193): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 7650: (204-208): Assertion checker does not yet support this expression. +// Warning 8364: (204-206): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 7650: (212-216): Assertion checker does not yet support this expression. +// Warning 8364: (212-214): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (220-224): Assertion checker does not yet support this expression. +// Warning 8364: (220-222): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 7650: (228-232): Assertion checker does not yet support this expression. +// Warning 8364: (228-230): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (244-248): Assertion checker does not yet support this expression. +// Warning 8364: (244-246): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 7650: (252-256): Assertion checker does not yet support this expression. +// Warning 8364: (252-254): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (260-264): Assertion checker does not yet support this expression. +// Warning 8364: (260-262): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 7650: (268-272): Assertion checker does not yet support this expression. +// Warning 8364: (268-270): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (277-281): Assertion checker does not yet support this expression. +// Warning 8364: (277-279): Assertion checker does not yet implement type struct C.S storage pointer +// Warning 4375: (277-281): Assertion checker does not support recursive structs. +// Warning 7650: (366-370): Assertion checker does not yet support this expression. +// Warning 8364: (366-368): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (380-384): Assertion checker does not yet support this expression. +// Warning 8364: (380-382): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_5.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_5.sol new file mode 100644 index 000000000..e86747344 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_5.sol @@ -0,0 +1,29 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + S[] a; + } + S[] sa; + S[][] sa2; + function f() public { + sa.push(); + sa2.push(); + sa2[0].push(); + sa2[0][0].a.push(); + assert(sa2[0][0].a.length == sa[0].a.length); + } +} +// ---- +// Warning 6328: (192-236): CHC: Assertion violation happens here. +// Warning 8364: (126-135): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (153-166): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (170-181): Assertion checker does not yet support this expression. +// Warning 8364: (170-179): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (170-188): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (170-181): Assertion checker does not support recursive structs. +// Warning 7650: (199-210): Assertion checker does not yet support this expression. +// Warning 8364: (199-208): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (221-228): Assertion checker does not yet support this expression. +// Warning 8364: (221-226): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_6.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_6.sol new file mode 100644 index 000000000..3999a4394 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_6.sol @@ -0,0 +1,66 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + S[] a; + } + S s1; + S s2; + function f() public { + s1.x = 10; + ++s1.x; + s1.x++; + s2.x = 20; + --s2.x; + s2.x--; + assert(s1.x == s2.x + 6); + assert(s1.a.length == s2.a.length); + delete s1; + assert(s1.x == 0); + } +} +// ---- +// Warning 4984: (200-208): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (185-209): CHC: Assertion violation happens here. +// Warning 6328: (213-247): CHC: Assertion violation happens here. +// Warning 6328: (264-281): CHC: Assertion violation happens here. +// Warning 8115: (81-85): Assertion checker does not yet support the type of this variable. +// Warning 8115: (88-92): Assertion checker does not yet support the type of this variable. +// Warning 7650: (119-123): Assertion checker does not yet support this expression. +// Warning 8364: (119-121): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (119-123): Assertion checker does not support recursive structs. +// Warning 7650: (134-138): Assertion checker does not yet support this expression. +// Warning 8364: (134-136): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (134-138): Assertion checker does not support recursive structs. +// Warning 7650: (142-146): Assertion checker does not yet support this expression. +// Warning 8364: (142-144): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (142-146): Assertion checker does not support recursive structs. +// Warning 7650: (152-156): Assertion checker does not yet support this expression. +// Warning 8364: (152-154): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (152-156): Assertion checker does not support recursive structs. +// Warning 7650: (167-171): Assertion checker does not yet support this expression. +// Warning 8364: (167-169): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (167-171): Assertion checker does not support recursive structs. +// Warning 7650: (175-179): Assertion checker does not yet support this expression. +// Warning 8364: (175-177): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (175-179): Assertion checker does not support recursive structs. +// Warning 7650: (192-196): Assertion checker does not yet support this expression. +// Warning 8364: (192-194): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (200-204): Assertion checker does not yet support this expression. +// Warning 8364: (200-202): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (220-224): Assertion checker does not yet support this expression. +// Warning 8364: (220-222): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (235-239): Assertion checker does not yet support this expression. +// Warning 8364: (235-237): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (258-260): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (271-275): Assertion checker does not yet support this expression. +// Warning 8364: (271-273): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4144: (132-138): BMC: Underflow (resulting value less than 0) happens here. +// Warning 2661: (132-138): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (142-148): BMC: Underflow (resulting value less than 0) happens here. +// Warning 2661: (142-148): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (165-171): BMC: Underflow (resulting value less than 0) happens here. +// Warning 2661: (165-171): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4144: (175-181): BMC: Underflow (resulting value less than 0) happens here. +// Warning 2661: (175-181): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_indirect_1.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_indirect_1.sol new file mode 100644 index 000000000..4bb810ec9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_indirect_1.sol @@ -0,0 +1,31 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + T[] a; + } + struct T { + uint y; + S[] a; + } + S s1; + S s2; + function f() public view { + assert(s1.x == s2.x); + assert(s1.a.length == s2.a.length); + } +} +// ---- +// Warning 6328: (158-178): CHC: Assertion violation happens here. +// Warning 6328: (182-216): CHC: Assertion violation happens here. +// Warning 8115: (115-119): Assertion checker does not yet support the type of this variable. +// Warning 8115: (122-126): Assertion checker does not yet support the type of this variable. +// Warning 7650: (165-169): Assertion checker does not yet support this expression. +// Warning 8364: (165-167): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (173-177): Assertion checker does not yet support this expression. +// Warning 8364: (173-175): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (189-193): Assertion checker does not yet support this expression. +// Warning 8364: (189-191): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (204-208): Assertion checker does not yet support this expression. +// Warning 8364: (204-206): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_indirect_2.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_indirect_2.sol new file mode 100644 index 000000000..ceb704bdd --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_recursive_indirect_2.sol @@ -0,0 +1,57 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + T[] a; + } + struct T { + uint y; + S[] a; + } + S s1; + S s2; + function f() public { + s1.a.push(); + s2.a.push(); + s1.a[0].a.push(); + s2.a[0].a.push(); + assert(s1.a[0].a[0].x == s2.a[0].a[0].x); + } +} +// ---- +// Warning 6328: (223-263): CHC: Assertion violation happens here. +// Warning 8115: (115-119): Assertion checker does not yet support the type of this variable. +// Warning 8115: (122-126): Assertion checker does not yet support the type of this variable. +// Warning 7650: (153-157): Assertion checker does not yet support this expression. +// Warning 8364: (153-155): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (153-164): Assertion checker does not yet implement type struct C.T storage ref +// Warning 4375: (153-157): Assertion checker does not support recursive structs. +// Warning 7650: (168-172): Assertion checker does not yet support this expression. +// Warning 8364: (168-170): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (168-179): Assertion checker does not yet implement type struct C.T storage ref +// Warning 4375: (168-172): Assertion checker does not support recursive structs. +// Warning 7650: (183-192): Assertion checker does not yet support this expression. +// Warning 7650: (183-187): Assertion checker does not yet support this expression. +// Warning 8364: (183-185): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (183-190): Assertion checker does not yet implement type struct C.T storage ref +// Warning 8364: (183-199): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (183-192): Assertion checker does not support recursive structs. +// Warning 7650: (203-212): Assertion checker does not yet support this expression. +// Warning 7650: (203-207): Assertion checker does not yet support this expression. +// Warning 8364: (203-205): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (203-210): Assertion checker does not yet implement type struct C.T storage ref +// Warning 8364: (203-219): Assertion checker does not yet implement type struct C.S storage ref +// Warning 4375: (203-212): Assertion checker does not support recursive structs. +// Warning 7650: (230-244): Assertion checker does not yet support this expression. +// Warning 7650: (230-239): Assertion checker does not yet support this expression. +// Warning 7650: (230-234): Assertion checker does not yet support this expression. +// Warning 8364: (230-232): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (230-237): Assertion checker does not yet implement type struct C.T storage ref +// Warning 8364: (230-242): Assertion checker does not yet implement type struct C.S storage ref +// Warning 7650: (248-262): Assertion checker does not yet support this expression. +// Warning 7650: (248-257): Assertion checker does not yet support this expression. +// Warning 7650: (248-252): Assertion checker does not yet support this expression. +// Warning 8364: (248-250): Assertion checker does not yet implement type struct C.S storage ref +// Warning 8364: (248-255): Assertion checker does not yet implement type struct C.T storage ref +// Warning 8364: (248-260): Assertion checker does not yet implement type struct C.S storage ref diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_return.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_return.sol new file mode 100644 index 000000000..352d29dc9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_return.sol @@ -0,0 +1,20 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + uint[] a; + } + function s() internal pure returns (S memory s1) { + s1.x = 42; + s1.a[2] = 43; + } + function f() public pure { + S memory s2 = s(); + assert(s2.x == 42); + assert(s2.a[2] == 43); + assert(s2.a[3] == 43); + } +} +// ---- +// Warning 6328: (265-286): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var.sol new file mode 100644 index 000000000..4f59676b8 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + uint[] a; + } + S s; + function f(uint _x) public { + s.x = _x; + s.a[0] = _x; + assert(s.a[1] == s.a[0]); + } +} +// ---- +// Warning 6328: (148-172): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol new file mode 100644 index 000000000..423e2e46c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol @@ -0,0 +1,25 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + uint[] a; + } + S s; + function f(uint _x) public { + s.a.pop(); + s.a.length; + s.a.push(); + s.x = _x; + s.a.pop(); + s.a.push(); + s.a.push(); + s.a[0] = _x; + assert(s.a[1] == s.a[0]); + s.a.pop(); + s.a.pop(); + } +} +// ---- +// Warning 2529: (121-130): CHC: Empty array "pop" detected here. +// Warning 6328: (230-254): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol new file mode 100644 index 000000000..161460c31 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol @@ -0,0 +1,22 @@ +pragma experimental SMTChecker; + +contract C { + struct S { + uint x; + uint[] a; + } + S s; + function f(uint _x) public { + s.x = _x; + s.a.pop(); + s.a.push(); + s.a.push(); + s.a[0] = _x; + assert(s.a[1] == s.a[0]); + s.a.pop(); + s.a.pop(); + } +} +// ---- +// Warning 2529: (133-142): CHC: Empty array "pop" detected here. +// Warning 6328: (189-213): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_unary_add.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_unary_add.sol new file mode 100644 index 000000000..93e6195f2 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_unary_add.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint x; + uint[] a; + } + function f(S memory s1, S memory s2) public pure { + delete s1; + s1.x++; + ++s1.x; + assert(s1.x == 2); + assert(s1.x == s2.x); + } +} +// ---- +// Warning 6328: (225-245): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_unary_sub.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_unary_sub.sol new file mode 100644 index 000000000..47713019e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_unary_sub.sol @@ -0,0 +1,19 @@ +pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint x; + uint[] a; + } + function f(S memory s1, S memory s2) public pure { + delete s1; + s1.x = 100; + s1.x--; + --s1.x; + assert(s1.x == 98); + assert(s1.x == s2.x); + } +} +// ---- +// Warning 6328: (240-260): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct_1.sol b/test/libsolidity/smtCheckerTests/types/struct_1.sol index e58d5c18f..99dc2b149 100644 --- a/test/libsolidity/smtCheckerTests/types/struct_1.sol +++ b/test/libsolidity/smtCheckerTests/types/struct_1.sol @@ -15,12 +15,7 @@ contract C } // ---- // Warning 2072: (157-170): Unused local variable. -// Warning 8115: (157-170): Assertion checker does not yet support the type of this variable. -// Warning 8364: (139-146): Assertion checker does not yet implement type struct C.S storage ref // Warning 8364: (149-150): Assertion checker does not yet implement type type(struct C.S storage pointer) -// Warning 8364: (149-153): Assertion checker does not yet implement type struct C.S memory // Warning 4639: (149-153): Assertion checker does not yet implement this expression. -// Warning 8364: (139-153): Assertion checker does not yet implement type struct C.S storage ref // Warning 8364: (173-174): Assertion checker does not yet implement type type(struct C.S storage pointer) -// Warning 8364: (173-177): Assertion checker does not yet implement type struct C.S memory // Warning 4639: (173-177): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/types/struct_array_branches_1d.sol b/test/libsolidity/smtCheckerTests/types/struct_array_branches_1d.sol index 7d5752c2b..96f8b1b7e 100644 --- a/test/libsolidity/smtCheckerTests/types/struct_array_branches_1d.sol +++ b/test/libsolidity/smtCheckerTests/types/struct_array_branches_1d.sol @@ -3,7 +3,7 @@ pragma experimental SMTChecker; contract C { struct S { uint[] a; } - function f(bool b) public { + function f(bool b) public pure { S memory c; c.a[0] = 0; if (b) @@ -14,21 +14,3 @@ contract C } } // ---- -// Warning 2018: (71-197): Function state mutability can be restricted to pure -// Warning 6328: (175-193): Assertion violation happens here -// Warning 8115: (101-111): Assertion checker does not yet support the type of this variable. -// Warning 7650: (115-118): Assertion checker does not yet support this expression. -// Warning 8364: (115-116): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (115-121): Assertion checker does not yet implement this expression. -// Warning 9056: (115-121): Assertion checker does not yet implement this expression. -// Warning 7650: (139-142): Assertion checker does not yet support this expression. -// Warning 8364: (139-140): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (139-145): Assertion checker does not yet implement this expression. -// Warning 9056: (139-145): Assertion checker does not yet implement this expression. -// Warning 7650: (161-164): Assertion checker does not yet support this expression. -// Warning 8364: (161-162): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (161-167): Assertion checker does not yet implement this expression. -// Warning 9056: (161-167): Assertion checker does not yet implement this expression. -// Warning 7650: (182-185): Assertion checker does not yet support this expression. -// Warning 8364: (182-183): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (182-188): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/types/struct_array_branches_2d.sol b/test/libsolidity/smtCheckerTests/types/struct_array_branches_2d.sol index d5fa12ed4..a1ceb4e80 100644 --- a/test/libsolidity/smtCheckerTests/types/struct_array_branches_2d.sol +++ b/test/libsolidity/smtCheckerTests/types/struct_array_branches_2d.sol @@ -3,7 +3,7 @@ pragma experimental SMTChecker; contract C { struct S { uint[][] a; } - function f(bool b) public { + function f(bool b) public pure { S memory c; c.a[0][0] = 0; if (b) @@ -14,21 +14,3 @@ contract C } } // ---- -// Warning 2018: (73-211): Function state mutability can be restricted to pure -// Warning 6328: (186-207): Assertion violation happens here -// Warning 8115: (103-113): Assertion checker does not yet support the type of this variable. -// Warning 7650: (117-120): Assertion checker does not yet support this expression. -// Warning 8364: (117-118): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (117-123): Assertion checker does not yet implement this expression. -// Warning 9056: (117-126): Assertion checker does not yet implement this expression. -// Warning 7650: (144-147): Assertion checker does not yet support this expression. -// Warning 8364: (144-145): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (144-150): Assertion checker does not yet implement this expression. -// Warning 9056: (144-153): Assertion checker does not yet implement this expression. -// Warning 7650: (169-172): Assertion checker does not yet support this expression. -// Warning 8364: (169-170): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (169-175): Assertion checker does not yet implement this expression. -// Warning 9056: (169-178): Assertion checker does not yet implement this expression. -// Warning 7650: (193-196): Assertion checker does not yet support this expression. -// Warning 8364: (193-194): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (193-199): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/types/struct_array_branches_3d.sol b/test/libsolidity/smtCheckerTests/types/struct_array_branches_3d.sol index 16b5fef4e..d23a95463 100644 --- a/test/libsolidity/smtCheckerTests/types/struct_array_branches_3d.sol +++ b/test/libsolidity/smtCheckerTests/types/struct_array_branches_3d.sol @@ -14,20 +14,3 @@ contract C } } // ---- -// Warning 6328: (202-226): Assertion violation happens here -// Warning 8115: (110-120): Assertion checker does not yet support the type of this variable. -// Warning 7650: (124-127): Assertion checker does not yet support this expression. -// Warning 8364: (124-125): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (124-130): Assertion checker does not yet implement this expression. -// Warning 9056: (124-136): Assertion checker does not yet implement this expression. -// Warning 7650: (154-157): Assertion checker does not yet support this expression. -// Warning 8364: (154-155): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (154-160): Assertion checker does not yet implement this expression. -// Warning 9056: (154-166): Assertion checker does not yet implement this expression. -// Warning 7650: (182-185): Assertion checker does not yet support this expression. -// Warning 8364: (182-183): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (182-188): Assertion checker does not yet implement this expression. -// Warning 9056: (182-194): Assertion checker does not yet implement this expression. -// Warning 7650: (209-212): Assertion checker does not yet support this expression. -// Warning 8364: (209-210): Assertion checker does not yet implement type struct C.S memory -// Warning 9118: (209-215): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_1_chain_1.sol b/test/libsolidity/smtCheckerTests/types/tuple_1_chain_1.sol index eded54d2e..b4db4cfd2 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_1_chain_1.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_1_chain_1.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 6838: (96-100): Condition is always true. +// Warning 6838: (96-100): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_1_chain_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_1_chain_2.sol index e35dff706..4ad41dd1f 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_1_chain_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_1_chain_2.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 6838: (96-100): Condition is always true. +// Warning 6838: (96-100): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_1_chain_n.sol b/test/libsolidity/smtCheckerTests/types/tuple_1_chain_n.sol index 5166ed1b6..85a1fe8fe 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_1_chain_n.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_1_chain_n.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 6838: (96-100): Condition is always true. +// Warning 6838: (96-100): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol index 089dcc5c1..c7e061e19 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol @@ -4,4 +4,4 @@ contract C { function f() public { (a).pop();} } // ---- -// Warning 2529: (78-87): Empty array "pop" detected here +// Warning 2529: (78-87): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol index 70e00939b..c8c066c15 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol @@ -4,4 +4,4 @@ contract C { function f() public { (((((a))))).pop();} } // ---- -// Warning 2529: (78-95): Empty array "pop" detected here +// Warning 2529: (78-95): CHC: Empty array "pop" detected here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_assignment_array_empty.sol b/test/libsolidity/smtCheckerTests/types/tuple_assignment_array_empty.sol index cac79a172..e6701730f 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_assignment_array_empty.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_assignment_array_empty.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (136-153): Assertion violation happens here +// Warning 6328: (136-153): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_assignment_compound.sol b/test/libsolidity/smtCheckerTests/types/tuple_assignment_compound.sol index 962060302..bb49ddb05 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_assignment_compound.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_assignment_compound.sol @@ -10,4 +10,4 @@ contract C } } // ---- -// Warning 6328: (122-136): Assertion violation happens here +// Warning 6328: (122-136): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_assignment_empty.sol b/test/libsolidity/smtCheckerTests/types/tuple_assignment_empty.sol index fd8d3485b..fe4ddde7c 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_assignment_empty.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_assignment_empty.sol @@ -11,4 +11,4 @@ contract C } } // ---- -// Warning 6328: (132-146): Assertion violation happens here +// Warning 6328: (132-146): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol index 9cea35cbb..0781b012b 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol @@ -15,4 +15,4 @@ contract C } } // ---- -// Warning 4984: (152-157): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning 4984: (152-157): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_empty.sol b/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_empty.sol index 8c0b2f059..16fb101a1 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_empty.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_empty.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (224-234): Assertion violation happens here +// Warning 6328: (224-234): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_1.sol b/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_1.sol index b0861b3b5..7bbaaec04 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_1.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_1.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6328: (157-171): Assertion violation happens here +// Warning 6328: (157-171): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_2.sol index 02a14c1b4..0670a558f 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_different_count_assignment_2.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 6328: (159-173): Assertion violation happens here +// Warning 6328: (159-173): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_extra_parens_7.sol b/test/libsolidity/smtCheckerTests/types/tuple_extra_parens_7.sol index 824d84c3e..254e58f7b 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_extra_parens_7.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_extra_parens_7.sol @@ -11,4 +11,3 @@ contract C { } } // ---- -// Warning 5084: (142-152): Type conversion is not yet fully supported and might yield false positives. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_function.sol b/test/libsolidity/smtCheckerTests/types/tuple_function.sol index 49ed1bb94..baf5f6f35 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_function.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_function.sol @@ -14,5 +14,5 @@ contract C } } // ---- -// Warning 6328: (182-196): Assertion violation happens here -// Warning 6328: (200-214): Assertion violation happens here +// Warning 6328: (182-196): CHC: Assertion violation happens here. +// Warning 6328: (200-214): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_function_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_function_2.sol index 13dd7b10d..088f93db6 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_function_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_function_2.sol @@ -14,4 +14,4 @@ contract C } } // ---- -// Warning 6328: (199-213): Assertion violation happens here +// Warning 6328: (199-213): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol b/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol index 5d0dc71c7..ead35dab0 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol @@ -16,5 +16,5 @@ contract C } } // ---- -// Warning 6328: (205-219): Assertion violation happens here -// Warning 6328: (223-237): Assertion violation happens here +// Warning 6328: (205-219): CHC: Assertion violation happens here. +// Warning 6328: (223-237): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_return_branch.sol b/test/libsolidity/smtCheckerTests/types/tuple_return_branch.sol index 1489eb87f..3ed532ccb 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_return_branch.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_return_branch.sol @@ -14,11 +14,6 @@ contract C { } } // ---- -// Warning 8115: (112-120): Assertion checker does not yet support the type of this variable. // Warning 8364: (137-138): Assertion checker does not yet implement type type(struct C.S storage pointer) -// Warning 8364: (137-141): Assertion checker does not yet implement type struct C.S memory // Warning 4639: (137-141): Assertion checker does not yet implement this expression. -// Warning 8115: (193-203): Assertion checker does not yet support the type of this variable. -// Warning 8364: (227-228): Assertion checker does not yet implement type struct C.S memory // Warning 4639: (137-141): Assertion checker does not yet implement this expression. -// Warning 6191: (227-228): Assertion checker does not yet implement type struct C.S memory diff --git a/test/libsolidity/smtCheckerTests/types/type_interfaceid.sol b/test/libsolidity/smtCheckerTests/types/type_interfaceid.sol new file mode 100644 index 000000000..396e84bca --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_interfaceid.sol @@ -0,0 +1,32 @@ +pragma experimental SMTChecker; + +interface I1 { +} + +interface I2 { + function f() external; +} + +interface I3 { + function f() external; + function g(uint, address) external; +} + +contract C { + function f() public pure { + assert(type(I1).interfaceId == 0); + assert(type(I2).interfaceId != 0); + assert(type(I2).interfaceId == 0x26121ff0); + assert(type(I2).interfaceId != 0); + assert(type(I3).interfaceId == 0x822b51c6); + } + function g() public pure { + assert(type(I1).interfaceId == type(I2).interfaceId); + } + function h() public pure { + assert(type(I2).interfaceId == type(I3).interfaceId); + } +} +// ---- +// Warning 6328: (449-501): CHC: Assertion violation happens here. +// Warning 6328: (536-588): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/type_meta_unsupported.sol b/test/libsolidity/smtCheckerTests/types/type_meta_unsupported.sol new file mode 100644 index 000000000..e9319b2d1 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_meta_unsupported.sol @@ -0,0 +1,19 @@ +pragma experimental SMTChecker; + +contract A { +} + +contract C { + function f() public pure { + assert(bytes(type(C).name).length != 0); + assert(type(A).creationCode.length != 0); + assert(type(A).runtimeCode.length != 0); + } +} +// ---- +// Warning 6328: (92-131): CHC: Assertion violation happens here. +// Warning 6328: (135-175): CHC: Assertion violation happens here. +// Warning 6328: (179-218): CHC: Assertion violation happens here. +// Warning 7507: (105-117): Assertion checker does not yet support this expression. +// Warning 7507: (142-162): Assertion checker does not yet support this expression. +// Warning 7507: (186-205): Assertion checker does not yet support this expression. diff --git a/test/libsolidity/smtCheckerTests/types/type_minmax.sol b/test/libsolidity/smtCheckerTests/types/type_minmax.sol new file mode 100644 index 000000000..f2802b7f2 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/type_minmax.sol @@ -0,0 +1,84 @@ +pragma experimental SMTChecker; + +contract C { + function f(uint a) public pure { + assert(a <= type(uint).max); + assert(a >= type(uint).min); + require(a <= type(uint64).max); + assert(a <= type(uint64).max); + assert(a <= type(uint32).max); + } + + function int_min() public pure { + int8 int8_min = type(int8).min; + assert(int8_min == -2**7); + + int16 int16_min = type(int16).min; + assert(int16_min == -2**15); + + int24 int24_min = type(int24).min; + assert(int24_min == -2**23); + + int32 int32_min = type(int32).min; + assert(int32_min == -2**31); + + int64 int64_min = type(int64).min; + assert(int64_min == -2**63); + + int256 int256_min = type(int256).min; + assert(int256_min == -2**255); + } + + function int_max() public pure { + int8 int8_max = type(int8).max; + assert(int8_max == 2**7-1); + + int16 int16_max = type(int16).max; + assert(int16_max == 2**15-1); + + int24 int24_max = type(int24).max; + assert(int24_max == 2**23-1); + + int32 int32_max = type(int32).max; + assert(int32_max == 2**31-1); + + int256 int256_max = type(int256).max; + assert(int256_max == 2**255-1); + } + + function uint_min() public pure { + uint8 uint8_min = type(uint8).min; + assert(uint8_min == 0); + + uint16 uint16_min = type(uint16).min; + assert(uint16_min == 0); + + uint24 uint24_min = type(uint24).min; + assert(uint24_min == 0); + + uint32 uint32_min = type(uint32).min; + assert(uint32_min == 0); + + uint256 uint256_min = type(uint256).min; + assert(uint256_min == 0); + } + + function uint_max() public pure { + uint8 uint8_max = type(uint8).max; + assert(uint8_max == 2**8-1); + + uint16 uint16_max = type(uint16).max; + assert(uint16_max == 2**16-1); + + uint24 uint24_max = type(uint24).max; + assert(uint24_max == 2**24-1); + + uint32 uint32_max = type(uint32).max; + assert(uint32_max == 2**32-1); + + uint256 uint256_max = type(uint256).max; + assert(uint256_max == 2**256-1); + } +} +// ---- +// Warning 6328: (211-240): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol index 00060c778..86e9e0d7c 100644 --- a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol +++ b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol @@ -5,5 +5,4 @@ contract C { } } // ---- -// Warning 6838: (94-100): Condition is always true. -// Warning 4588: (104-112): Assertion checker does not yet implement this type of function call. +// Warning 6838: (94-100): BMC: Condition is always true. diff --git a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol index 9d52fa7c5..a09d00cea 100644 --- a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol +++ b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol @@ -5,5 +5,4 @@ contract C { } } // ---- -// Warning 6838: (109-115): Condition is always false. -// Warning 4588: (119-127): Assertion checker does not yet implement this type of function call. +// Warning 6838: (109-115): BMC: Condition is always false. diff --git a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol index ba6b7f0f6..709fcb1b4 100644 --- a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol +++ b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol @@ -6,4 +6,3 @@ contract C { } } // ---- -// Warning 4588: (136-144): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol b/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol index 4226f85e8..1b8433580 100644 --- a/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol +++ b/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol @@ -3,4 +3,4 @@ contract C { function f(uint a) public pure { assert(a == 2); } } // ---- -// Warning 6328: (82-96): Assertion violation happens here +// Warning 6328: (82-96): CHC: Assertion violation happens here. diff --git a/test/libsolidity/syntaxTests/constructor/msg_value_non_payable.sol b/test/libsolidity/syntaxTests/constructor/msg_value_non_payable.sol new file mode 100644 index 000000000..8392cdf63 --- /dev/null +++ b/test/libsolidity/syntaxTests/constructor/msg_value_non_payable.sol @@ -0,0 +1,8 @@ +contract C { + uint256 value; + constructor() { + value = msg.value; + } +} +// ---- +// TypeError 5887: (68-77): "msg.value" and "callvalue()" can only be used in payable constructors. Make the constructor "payable" to avoid this error. diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_array_of_string_literals_to_calldata_string.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_array_of_string_literals_to_calldata_string.sol new file mode 100644 index 000000000..328a86f79 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_array_of_string_literals_to_calldata_string.sol @@ -0,0 +1,9 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f() public pure returns(string[5] calldata) { + return ["h", "e", "l", "l", "o"]; + } +} +// ---- +// TypeError 6359: (122-147): Return argument type string memory[5] memory is not implicitly convertible to expected type (type of first return variable) string calldata[5] calldata. diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_string_literal_to_calldata_string.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_string_literal_to_calldata_string.sol new file mode 100644 index 000000000..166ebffb0 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_string_literal_to_calldata_string.sol @@ -0,0 +1,17 @@ +contract C { + function f1() public pure returns(string calldata) { + return "hello"; + } + + function f2() public pure returns(string calldata) { + return unicode"hello"; + } + + function f3() public pure returns(bytes calldata) { + return hex"68656c6c6f"; + } +} +// ---- +// TypeError 6359: (85-92): Return argument type literal_string "hello" is not implicitly convertible to expected type (type of first return variable) string calldata. +// TypeError 6359: (173-187): Return argument type literal_string "hello" is not implicitly convertible to expected type (type of first return variable) string calldata. +// TypeError 6359: (267-282): Return argument type literal_string "hello" is not implicitly convertible to expected type (type of first return variable) bytes calldata. diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_string_literal_to_calldata_string_in_function_parameter.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_string_literal_to_calldata_string_in_function_parameter.sol new file mode 100644 index 000000000..bf58cba42 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_string_literal_to_calldata_string_in_function_parameter.sol @@ -0,0 +1,14 @@ +contract C { + function g(string calldata _s) public {} + function h(bytes calldata _b) public {} + + function f() public { + g("hello"); + g(unicode"hello"); + h(hex"68656c6c6f"); + } +} +// ---- +// TypeError 9553: (139-146): Invalid type for argument in function call. Invalid implicit conversion from literal_string "hello" to string calldata requested. +// TypeError 9553: (159-173): Invalid type for argument in function call. Invalid implicit conversion from literal_string "hello" to string calldata requested. +// TypeError 9553: (186-201): Invalid type for argument in function call. Invalid implicit conversion from literal_string "hello" to bytes calldata requested. diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol new file mode 100644 index 000000000..b2f5ba881 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol @@ -0,0 +1,27 @@ +contract D {} + +contract C { + C c; + D d; + + function foo() public { + // Current instance of the current contract vs super + super != this; + this != super; + + // Different instance of the current contract vs super + super != c; + c != super; + + // Instance of an unrelated contract vs super + super != d; + d != super; + } +} +// ---- +// TypeError 2271: (144-157): Operator != not compatible with types contract super C and contract C +// TypeError 2271: (167-180): Operator != not compatible with types contract C and contract super C +// TypeError 2271: (254-264): Operator != not compatible with types contract super C and contract C +// TypeError 2271: (274-284): Operator != not compatible with types contract C and contract super C +// TypeError 2271: (349-359): Operator != not compatible with types contract super C and contract D +// TypeError 2271: (369-379): Operator != not compatible with types contract D and contract super C diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol new file mode 100644 index 000000000..2cb104dbd --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol @@ -0,0 +1,56 @@ +contract C { + function foo() public { + super << this; + super >> this; + super ^ this; + super | this; + super & this; + + super * this; + super / this; + super % this; + super - this; + super + this; + super ** this; + + super == this; + super != this; + super >= this; + super <= this; + super < this; + super > this; + + super || this; + super && this; + + super -= this; + super += this; + + true ? super : this; + } +} +// ---- +// TypeError 2271: (49-62): Operator << not compatible with types contract super C and contract C +// TypeError 2271: (72-85): Operator >> not compatible with types contract super C and contract C +// TypeError 2271: (95-107): Operator ^ not compatible with types contract super C and contract C +// TypeError 2271: (117-129): Operator | not compatible with types contract super C and contract C +// TypeError 2271: (139-151): Operator & not compatible with types contract super C and contract C +// TypeError 2271: (162-174): Operator * not compatible with types contract super C and contract C +// TypeError 2271: (184-196): Operator / not compatible with types contract super C and contract C +// TypeError 2271: (206-218): Operator % not compatible with types contract super C and contract C +// TypeError 2271: (228-240): Operator - not compatible with types contract super C and contract C +// TypeError 2271: (250-262): Operator + not compatible with types contract super C and contract C +// TypeError 2271: (272-285): Operator ** not compatible with types contract super C and contract C +// TypeError 2271: (296-309): Operator == not compatible with types contract super C and contract C +// TypeError 2271: (319-332): Operator != not compatible with types contract super C and contract C +// TypeError 2271: (342-355): Operator >= not compatible with types contract super C and contract C +// TypeError 2271: (365-378): Operator <= not compatible with types contract super C and contract C +// TypeError 2271: (388-400): Operator < not compatible with types contract super C and contract C +// TypeError 2271: (410-422): Operator > not compatible with types contract super C and contract C +// TypeError 2271: (433-446): Operator || not compatible with types contract super C and contract C +// TypeError 2271: (456-469): Operator && not compatible with types contract super C and contract C +// TypeError 4247: (480-485): Expression has to be an lvalue. +// TypeError 7366: (480-493): Operator -= not compatible with types contract super C and contract C +// TypeError 4247: (503-508): Expression has to be an lvalue. +// TypeError 7366: (503-516): Operator += not compatible with types contract super C and contract C +// TypeError 1080: (527-546): True expression's type contract super C does not match false expression's type contract C. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/082_anonymous_event_four_indexed.sol b/test/libsolidity/syntaxTests/events/anonymous_event_four_indexed.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/082_anonymous_event_four_indexed.sol rename to test/libsolidity/syntaxTests/events/anonymous_event_four_indexed.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/083_anonymous_event_too_many_indexed.sol b/test/libsolidity/syntaxTests/events/anonymous_event_too_many_indexed.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/083_anonymous_event_too_many_indexed.sol rename to test/libsolidity/syntaxTests/events/anonymous_event_too_many_indexed.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/087_double_event_declaration.sol b/test/libsolidity/syntaxTests/events/double_event_declaration.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/087_double_event_declaration.sol rename to test/libsolidity/syntaxTests/events/double_event_declaration.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/088_double_event_declaration_ignores_anonymous.sol b/test/libsolidity/syntaxTests/events/double_event_declaration_ignores_anonymous.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/088_double_event_declaration_ignores_anonymous.sol rename to test/libsolidity/syntaxTests/events/double_event_declaration_ignores_anonymous.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/089_double_event_declaration_ignores_indexed.sol b/test/libsolidity/syntaxTests/events/double_event_declaration_ignores_indexed.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/089_double_event_declaration_ignores_indexed.sol rename to test/libsolidity/syntaxTests/events/double_event_declaration_ignores_indexed.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/080_event.sol b/test/libsolidity/syntaxTests/events/event.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/080_event.sol rename to test/libsolidity/syntaxTests/events/event.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/090_event_call.sol b/test/libsolidity/syntaxTests/events/event_call.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/090_event_call.sol rename to test/libsolidity/syntaxTests/events/event_call.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/561_event_emit_complex.sol b/test/libsolidity/syntaxTests/events/event_emit_complex.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/561_event_emit_complex.sol rename to test/libsolidity/syntaxTests/events/event_emit_complex.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/562_event_emit_foreign_class.sol b/test/libsolidity/syntaxTests/events/event_emit_foreign_class.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/562_event_emit_foreign_class.sol rename to test/libsolidity/syntaxTests/events/event_emit_foreign_class.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/560_event_emit_simple.sol b/test/libsolidity/syntaxTests/events/event_emit_simple.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/560_event_emit_simple.sol rename to test/libsolidity/syntaxTests/events/event_emit_simple.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/091_event_function_inheritance_clash.sol b/test/libsolidity/syntaxTests/events/event_function_inheritance_clash.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/091_event_function_inheritance_clash.sol rename to test/libsolidity/syntaxTests/events/event_function_inheritance_clash.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/094_event_inheritance.sol b/test/libsolidity/syntaxTests/events/event_inheritance.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/094_event_inheritance.sol rename to test/libsolidity/syntaxTests/events/event_inheritance.sol diff --git a/test/libsolidity/syntaxTests/events/event_named_arguments_in_any_order.sol b/test/libsolidity/syntaxTests/events/event_named_arguments_in_any_order.sol new file mode 100644 index 000000000..372659e89 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_named_arguments_in_any_order.sol @@ -0,0 +1,13 @@ +contract C { + event e(uint u, string s, bool b); + + function call() public { + emit e({s: "abc", u: 1, b: true}); + emit e({s: "abc", b: true, u: 1}); + emit e({u: 1, s: "abc", b: true}); + emit e({b: true, s: "abc", u: 1}); + emit e({u: 1, b: true, s: "abc"}); + emit e({b: true, u: 1, s: "abc"}); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/events/event_overload_named_arguments_ambiguous.sol b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_ambiguous.sol new file mode 100644 index 000000000..28ee39e15 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_ambiguous.sol @@ -0,0 +1,10 @@ +contract C { + event e(uint u, string s); + event e(string s, uint u); + + function call() public { + emit e({u: 2, s: "abc"}); + } +} +// ---- +// TypeError 4487: (118-119): No unique declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/events/event_overload_named_arguments_ambiguous_implicit_conversion.sol b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_ambiguous_implicit_conversion.sol new file mode 100644 index 000000000..2c7884a9d --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_ambiguous_implicit_conversion.sol @@ -0,0 +1,10 @@ +contract C { + event e(uint u, string s); + event e(bytes s, int u); + + function call() public { + emit e({u: 2, s: "abc"}); + } +} +// ---- +// TypeError 4487: (116-117): No unique declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/events/event_overload_named_arguments_in_any_order.sol b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_in_any_order.sol new file mode 100644 index 000000000..e1d4eb343 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_in_any_order.sol @@ -0,0 +1,14 @@ +contract C { + event e(uint u, string s, bool b); + event e(uint u, uint s, uint b); + + function call() public { + emit e({s: "abc", u: 1, b: true}); + emit e({s: "abc", b: true, u: 1}); + emit e({u: 1, s: "abc", b: true}); + emit e({b: true, s: "abc", u: 1}); + emit e({u: 1, b: true, s: "abc"}); + emit e({b: true, u: 1, s: "abc"}); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/events/event_overload_named_arguments_wrong_types.sol b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_wrong_types.sol new file mode 100644 index 000000000..abee5dff1 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_overload_named_arguments_wrong_types.sol @@ -0,0 +1,10 @@ +contract C { + event e(uint u, string s); + event e(string s, uint u); + + function call() public { + emit e({s: 2, u: "abc"}); + } +} +// ---- +// TypeError 9322: (118-119): No matching declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/587_event_param_type_outside_storage.sol b/test/libsolidity/syntaxTests/events/event_param_type_outside_storage.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/587_event_param_type_outside_storage.sol rename to test/libsolidity/syntaxTests/events/event_param_type_outside_storage.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/081_event_too_many_indexed.sol b/test/libsolidity/syntaxTests/events/event_too_many_indexed.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/081_event_too_many_indexed.sol rename to test/libsolidity/syntaxTests/events/event_too_many_indexed.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/563_event_without_emit_deprecated.sol b/test/libsolidity/syntaxTests/events/event_without_emit_deprecated.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/563_event_without_emit_deprecated.sol rename to test/libsolidity/syntaxTests/events/event_without_emit_deprecated.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/084_events_with_same_name.sol b/test/libsolidity/syntaxTests/events/events_with_same_name.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/084_events_with_same_name.sol rename to test/libsolidity/syntaxTests/events/events_with_same_name.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/086_events_with_same_name_different_types.sol b/test/libsolidity/syntaxTests/events/events_with_same_name_different_types.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/086_events_with_same_name_different_types.sol rename to test/libsolidity/syntaxTests/events/events_with_same_name_different_types.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/085_events_with_same_name_unnamed_arguments.sol b/test/libsolidity/syntaxTests/events/events_with_same_name_unnamed_arguments.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/085_events_with_same_name_unnamed_arguments.sol rename to test/libsolidity/syntaxTests/events/events_with_same_name_unnamed_arguments.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/093_function_event_in_contract_clash.sol b/test/libsolidity/syntaxTests/events/function_event_in_contract_clash.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/093_function_event_in_contract_clash.sol rename to test/libsolidity/syntaxTests/events/function_event_in_contract_clash.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/092_function_event_inheritance_clash.sol b/test/libsolidity/syntaxTests/events/function_event_inheritance_clash.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/092_function_event_inheritance_clash.sol rename to test/libsolidity/syntaxTests/events/function_event_inheritance_clash.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/095_multiple_events_argument_clash.sol b/test/libsolidity/syntaxTests/events/multiple_events_argument_clash.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/095_multiple_events_argument_clash.sol rename to test/libsolidity/syntaxTests/events/multiple_events_argument_clash.sol diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_different_integer_types.sol b/test/libsolidity/syntaxTests/freeFunctions/free_different_integer_types.sol new file mode 100644 index 000000000..20d9596bc --- /dev/null +++ b/test/libsolidity/syntaxTests/freeFunctions/free_different_integer_types.sol @@ -0,0 +1,4 @@ +function f(uint24) {} +function f(uint16) {} +function f(int24) {} +function f(bool) {} diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_function_namesake_different_parameter_types.sol b/test/libsolidity/syntaxTests/freeFunctions/free_function_namesake_different_parameter_types.sol new file mode 100644 index 000000000..bde560ccb --- /dev/null +++ b/test/libsolidity/syntaxTests/freeFunctions/free_function_namesake_different_parameter_types.sol @@ -0,0 +1,11 @@ +function g() pure returns (uint) { return 1; } +function g() pure returns (string memory) { return "1"; } +contract C { + function foo() public pure returns (uint) { + string memory s = g(); + return 100/g(); + } +} +// ---- +// DeclarationError 1686: (0-46): Function with same name and parameter types defined twice. +// TypeError 9574: (168-189): Type uint256 is not implicitly convertible to expected type string memory. diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_identical.sol b/test/libsolidity/syntaxTests/freeFunctions/free_identical.sol new file mode 100644 index 000000000..58d5a5b5b --- /dev/null +++ b/test/libsolidity/syntaxTests/freeFunctions/free_identical.sol @@ -0,0 +1,4 @@ +function f() pure returns (uint) { return 1337; } +function f() pure returns (uint) { return 42; } +// ---- +// DeclarationError 1686: (0-49): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_identical_multiple.sol b/test/libsolidity/syntaxTests/freeFunctions/free_identical_multiple.sol new file mode 100644 index 000000000..2eb8b6b4b --- /dev/null +++ b/test/libsolidity/syntaxTests/freeFunctions/free_identical_multiple.sol @@ -0,0 +1,5 @@ +function f() pure returns (uint) { return 1337; } +function f() pure returns (uint) { return 42; } +function f() pure returns (uint) { return 1; } +// ---- +// DeclarationError 1686: (0-49): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_namesake_contract_function.sol b/test/libsolidity/syntaxTests/freeFunctions/free_namesake_contract_function.sol new file mode 100644 index 000000000..4212154cc --- /dev/null +++ b/test/libsolidity/syntaxTests/freeFunctions/free_namesake_contract_function.sol @@ -0,0 +1,8 @@ +function f() pure returns (uint) { return 1337; } +contract C { + function f() public pure returns (uint) { + return f(); + } +} +// ---- +// Warning 2519: (65-126): This declaration shadows an existing declaration. diff --git a/test/libsolidity/syntaxTests/freeFunctions/free_redefinition.sol b/test/libsolidity/syntaxTests/freeFunctions/free_redefinition.sol new file mode 100644 index 000000000..91c53aff1 --- /dev/null +++ b/test/libsolidity/syntaxTests/freeFunctions/free_redefinition.sol @@ -0,0 +1,9 @@ +function f() pure returns (uint) { return 1337; } +function f() view returns (uint) { return 42; } +contract C { + function g() public pure virtual returns (uint) { + return f(); + } +} +// ---- +// DeclarationError 1686: (0-49): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/functionCalls/msg_value_non_payable.sol b/test/libsolidity/syntaxTests/functionCalls/msg_value_non_payable.sol new file mode 100644 index 000000000..281e74882 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/msg_value_non_payable.sol @@ -0,0 +1,7 @@ +contract C { + function get() public view returns(uint256) { + return msg.value; + } +} +// ---- +// TypeError 5887: (78-87): "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. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_duplicate_parameter.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/102_duplicate_parameter_names_in_named_args.sol rename to test/libsolidity/syntaxTests/functionCalls/named_arguments_duplicate_parameter.sol diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/101_empty_in_named_args.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_empty.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/101_empty_in_named_args.sol rename to test/libsolidity/syntaxTests/functionCalls/named_arguments_empty.sol diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_in_any_order.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_in_any_order.sol new file mode 100644 index 000000000..695bd5ac5 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_in_any_order.sol @@ -0,0 +1,13 @@ +contract C { + function f(uint u, string memory s, bool b) internal {} + + function call() public { + f({s: "abc", u: 1, b: true}); + f({s: "abc", b: true, u: 1}); + f({u: 1, s: "abc", b: true}); + f({b: true, s: "abc", u: 1}); + f({u: 1, b: true, s: "abc"}); + f({b: true, u: 1, s: "abc"}); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_invalid_name.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_invalid_name.sol new file mode 100644 index 000000000..0c19ff416 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_invalid_name.sol @@ -0,0 +1,13 @@ +contract test { + function f(uint a, bool b, bytes memory c, uint d, bool e) public returns (uint r) { + if (b && !e) + r = a + d; + else + r = c.length; + } + function g() public returns (uint r) { + r = f({c: "abc", x: 1, e: 2, a: 11, b: 12}); + } +} +// ---- +// TypeError 4974: (249-288): Named argument "x" does not match function declaration. diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_ambiguous.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_ambiguous.sol new file mode 100644 index 000000000..85acad306 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_ambiguous.sol @@ -0,0 +1,11 @@ +contract C { + function f(uint x, string memory y, bool z) internal {} + function f(string memory y, uint x, bool z) internal {} + function f(bool z, string memory y, uint x) internal {} + + function call() internal { + f({x: 1, y: "abc", z: true}); + } +} +// ---- +// TypeError 4487: (233-234): No unique declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_ambiguous_implicit_conversion.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_ambiguous_implicit_conversion.sol new file mode 100644 index 000000000..4e44c54e1 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_ambiguous_implicit_conversion.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint x, string memory y) internal {} + function f(bytes memory y, int x) internal {} + + function call() internal { + f({x: 1, y: "abc"}); + } +} +// ---- +// TypeError 4487: (155-156): No unique declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_right_names_wrong_order.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_right_names_wrong_order.sol new file mode 100644 index 000000000..fc2b413ab --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_right_names_wrong_order.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint x, string memory y, bool z) internal {} + function f(uint x, uint y, uint z) internal {} + + function call() internal { + f({y: 1, x: "abc", z: true}); + } +} +// ---- +// TypeError 9322: (164-165): No matching declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_wrong_names.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_wrong_names.sol new file mode 100644 index 000000000..951de8678 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_failing_wrong_names.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint x, string memory y, bool z) internal {} + function f(uint x, uint y, uint z) internal {} + + function call() internal { + f({a: 1, b: "abc", c: true}); + } +} +// ---- +// TypeError 9322: (164-165): No matching declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_in_any_order.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_in_any_order.sol new file mode 100644 index 000000000..e6ba976d0 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionCalls/named_arguments_overload_in_any_order.sol @@ -0,0 +1,14 @@ +contract C { + function f(uint u, string memory s, bool b) internal {} + function f(uint u, uint s, uint b) internal {} + + function call() public { + f({s: "abc", u: 1, b: true}); + f({s: "abc", b: true, u: 1}); + f({u: 1, s: "abc", b: true}); + f({b: true, s: "abc", u: 1}); + f({u: 1, b: true, s: "abc"}); + f({b: true, u: 1, s: "abc"}); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/100_error_count_in_named_args.sol b/test/libsolidity/syntaxTests/functionCalls/named_arguments_wrong_count.sol similarity index 100% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/100_error_count_in_named_args.sol rename to test/libsolidity/syntaxTests/functionCalls/named_arguments_wrong_count.sol diff --git a/test/libsolidity/syntaxTests/iceRegressionTests/oversized_var.sol b/test/libsolidity/syntaxTests/iceRegressionTests/oversized_var.sol index 4c3d45385..761e60a1a 100644 --- a/test/libsolidity/syntaxTests/iceRegressionTests/oversized_var.sol +++ b/test/libsolidity/syntaxTests/iceRegressionTests/oversized_var.sol @@ -12,7 +12,9 @@ contract b { } } // ---- -// Warning 3408: (66-69): Variable "d" 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 in small quantities per transaction. -// Warning 2332: (111-112): Type "struct b.c" 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 in small quantities per transaction. -// Warning 2332: (152-169): Type "function ()[984770902183611232881]" 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 in small quantities per transaction. +// Warning 7325: (66-67): Type struct b.c 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 in small quantities per transaction. +// Warning 7325: (66-67): Type uint256[14474011154664524427946373126085988481658748083205070504932198000989141204992] 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 in small quantities per transaction. +// Warning 7325: (111-112): Type struct b.c 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 in small quantities per transaction. +// Warning 7325: (111-112): Type uint256[14474011154664524427946373126085988481658748083205070504932198000989141204992] 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 in small quantities per transaction. +// Warning 7325: (152-169): Type function ()[984770902183611232881] 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 in small quantities per transaction. // Warning 2072: (152-180): Unused local variable. diff --git a/test/libsolidity/syntaxTests/indexing/array_multidim_rational.sol b/test/libsolidity/syntaxTests/indexing/array_multidim_rational.sol index ace6dbdda..b0d4dbb10 100644 --- a/test/libsolidity/syntaxTests/indexing/array_multidim_rational.sol +++ b/test/libsolidity/syntaxTests/indexing/array_multidim_rational.sol @@ -5,7 +5,7 @@ contract C { } } // ---- -// TypeError 7407: (67-72): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. -// TypeError 7407: (74-79): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. +// TypeError 7407: (67-72): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. +// TypeError 7407: (74-79): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. // TypeError 7407: (81-90): Type rational_const 9485...(73 digits omitted)...5712 / 5 is not implicitly convertible to expected type uint256. // TypeError 6318: (65-91): Index expression cannot be represented as an unsigned integer. diff --git a/test/libsolidity/syntaxTests/indexing/array_multim_overflow_index.sol b/test/libsolidity/syntaxTests/indexing/array_multim_overflow_index.sol index e7701e7ab..0f18ec4d2 100644 --- a/test/libsolidity/syntaxTests/indexing/array_multim_overflow_index.sol +++ b/test/libsolidity/syntaxTests/indexing/array_multim_overflow_index.sol @@ -5,7 +5,7 @@ contract C { } } // ---- -// TypeError 7407: (67-72): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. -// TypeError 7407: (74-79): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. -// TypeError 7407: (81-90): Type int_const -189...(75 digits omitted)...1423 is not implicitly convertible to expected type uint256. +// TypeError 7407: (67-72): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. +// TypeError 7407: (74-79): Type int_const 1897...(74 digits omitted)...1424 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. +// TypeError 7407: (81-90): Type int_const -189...(75 digits omitted)...1423 is not implicitly convertible to expected type uint256. Cannot implicitly convert signed literal to unsigned type. // TypeError 6318: (65-91): Index expression cannot be represented as an unsigned integer. diff --git a/test/libsolidity/syntaxTests/indexing/array_negative_index.sol b/test/libsolidity/syntaxTests/indexing/array_negative_index.sol index 17ea84088..810ad3b73 100644 --- a/test/libsolidity/syntaxTests/indexing/array_negative_index.sol +++ b/test/libsolidity/syntaxTests/indexing/array_negative_index.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 7407: (67-69): Type int_const -1 is not implicitly convertible to expected type uint256. +// TypeError 7407: (67-69): Type int_const -1 is not implicitly convertible to expected type uint256. Cannot implicitly convert signed literal to unsigned type. diff --git a/test/libsolidity/syntaxTests/indexing/array_noninteger_index.sol b/test/libsolidity/syntaxTests/indexing/array_noninteger_index.sol index 086cd42a4..c1a62ffb4 100644 --- a/test/libsolidity/syntaxTests/indexing/array_noninteger_index.sol +++ b/test/libsolidity/syntaxTests/indexing/array_noninteger_index.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 7407: (67-178): Type int_const 8888...(103 digits omitted)...8888 is not implicitly convertible to expected type uint256. +// TypeError 7407: (67-178): Type int_const 8888...(103 digits omitted)...8888 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. diff --git a/test/libsolidity/syntaxTests/indexing/fixedbytes_negative_index.sol b/test/libsolidity/syntaxTests/indexing/fixedbytes_negative_index.sol index aeb5fc873..4d6e8545e 100644 --- a/test/libsolidity/syntaxTests/indexing/fixedbytes_negative_index.sol +++ b/test/libsolidity/syntaxTests/indexing/fixedbytes_negative_index.sol @@ -5,5 +5,5 @@ contract C { } } // ---- -// TypeError 7407: (58-60): Type int_const -1 is not implicitly convertible to expected type uint256. +// TypeError 7407: (58-60): Type int_const -1 is not implicitly convertible to expected type uint256. Cannot implicitly convert signed literal to unsigned type. // TypeError 6318: (56-61): Index expression cannot be represented as an unsigned integer. diff --git a/test/libsolidity/syntaxTests/indexing/fixedbytes_noninteger_index.sol b/test/libsolidity/syntaxTests/indexing/fixedbytes_noninteger_index.sol index 2b874eab2..c73064245 100644 --- a/test/libsolidity/syntaxTests/indexing/fixedbytes_noninteger_index.sol +++ b/test/libsolidity/syntaxTests/indexing/fixedbytes_noninteger_index.sol @@ -5,5 +5,5 @@ contract C { } } // ---- -// TypeError 7407: (58-169): Type int_const 8888...(103 digits omitted)...8888 is not implicitly convertible to expected type uint256. +// TypeError 7407: (58-169): Type int_const 8888...(103 digits omitted)...8888 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. // TypeError 6318: (56-170): Index expression cannot be represented as an unsigned integer. diff --git a/test/libsolidity/syntaxTests/indexing/index_range_access_assert.sol b/test/libsolidity/syntaxTests/indexing/index_range_access_assert.sol new file mode 100644 index 000000000..346cdd973 --- /dev/null +++ b/test/libsolidity/syntaxTests/indexing/index_range_access_assert.sol @@ -0,0 +1,6 @@ +// Used to trigger assert +contract s{} +function f() {s[:][];} +// ---- +// TypeError 1760: (53-57): Types cannot be sliced. +// TypeError 2876: (53-59): Index access for contracts or libraries is not possible. diff --git a/test/libsolidity/syntaxTests/indexing/struct_array_noninteger_index.sol b/test/libsolidity/syntaxTests/indexing/struct_array_noninteger_index.sol index 93f81abbd..024c58940 100644 --- a/test/libsolidity/syntaxTests/indexing/struct_array_noninteger_index.sol +++ b/test/libsolidity/syntaxTests/indexing/struct_array_noninteger_index.sol @@ -7,4 +7,4 @@ contract test { } // ---- -// TypeError 7407: (101-241): Type int_const 7555...(132 digits omitted)...5555 is not implicitly convertible to expected type uint256. +// TypeError 7407: (101-241): Type int_const 7555...(132 digits omitted)...5555 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. diff --git a/test/libsolidity/syntaxTests/inheritance/virtual/modifier_virtual_err.sol b/test/libsolidity/syntaxTests/inheritance/virtual/modifier_virtual_err.sol new file mode 100644 index 000000000..85824c86b --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/virtual/modifier_virtual_err.sol @@ -0,0 +1,7 @@ +library test { + modifier m virtual; + function f() m public { + } +} +// ---- +// TypeError 3275: (19-38): Modifiers in a library cannot be virtual. diff --git a/test/libsolidity/syntaxTests/largeTypes/large_storage_array_mapping.sol b/test/libsolidity/syntaxTests/largeTypes/large_storage_array_mapping.sol index 2dfc50a41..08f8a46b3 100644 --- a/test/libsolidity/syntaxTests/largeTypes/large_storage_array_mapping.sol +++ b/test/libsolidity/syntaxTests/largeTypes/large_storage_array_mapping.sol @@ -2,4 +2,4 @@ contract C { mapping(uint => uint[2**100]) x; } // ---- -// Warning 7325: (17-46): Type "uint256[1267650600228229401496703205376]" 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 in small quantities per transaction. +// Warning 7325: (17-46): Type uint256[1267650600228229401496703205376] 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 in small quantities per transaction. diff --git a/test/libsolidity/syntaxTests/largeTypes/large_storage_array_simple.sol b/test/libsolidity/syntaxTests/largeTypes/large_storage_array_simple.sol index 3f7499ca2..3fc91da4d 100644 --- a/test/libsolidity/syntaxTests/largeTypes/large_storage_array_simple.sol +++ b/test/libsolidity/syntaxTests/largeTypes/large_storage_array_simple.sol @@ -2,4 +2,4 @@ contract C { uint[2**64] x; } // ---- -// Warning 3408: (17-30): Variable "x" 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 in small quantities per transaction. +// Warning 7325: (17-28): Type uint256[18446744073709551616] 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 in small quantities per transaction. diff --git a/test/libsolidity/syntaxTests/largeTypes/large_storage_arrays_struct.sol b/test/libsolidity/syntaxTests/largeTypes/large_storage_arrays_struct.sol index 285b99deb..e2488adc0 100644 --- a/test/libsolidity/syntaxTests/largeTypes/large_storage_arrays_struct.sol +++ b/test/libsolidity/syntaxTests/largeTypes/large_storage_arrays_struct.sol @@ -3,4 +3,4 @@ contract C { S[2**20] x; } // ---- -// Warning 3408: (64-74): Variable "x" 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 in small quantities per transaction. +// Warning 7325: (64-72): Type struct C.S[1048576] 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 in small quantities per transaction. diff --git a/test/libsolidity/syntaxTests/largeTypes/large_storage_structs.sol b/test/libsolidity/syntaxTests/largeTypes/large_storage_structs.sol index a29401d94..cbc912a35 100644 --- a/test/libsolidity/syntaxTests/largeTypes/large_storage_structs.sol +++ b/test/libsolidity/syntaxTests/largeTypes/large_storage_structs.sol @@ -55,14 +55,20 @@ contract C { Q4 q4; } // ---- -// Warning 3408: (106-111): Variable "s0" 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 in small quantities per transaction. -// Warning 3408: (171-176): Variable "s1" 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 in small quantities per transaction. -// Warning 7325: (341-343): Type "C.P[103]" 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 in small quantities per transaction. -// Warning 7325: (341-343): Type "C.P[104]" 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 in small quantities per transaction. -// Warning 3408: (505-510): Variable "q0" 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 in small quantities per transaction. -// Warning 7325: (505-507): Type "uint256[100000000000000000002]" 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 in small quantities per transaction. -// Warning 7325: (505-507): Type "uint256[100000000000000000004]" 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 in small quantities per transaction. -// Warning 3408: (576-581): Variable "q1" 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 in small quantities per transaction. -// Warning 7325: (647-649): Type "uint256[100000000000000000006]" 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 in small quantities per transaction. -// Warning 3408: (715-720): Variable "q3" 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 in small quantities per transaction. -// Warning 7325: (783-785): Type "uint256[100000000000000000008]" 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 in small quantities per transaction. +// Warning 7325: (106-108): Type struct C.S0 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 in small quantities per transaction. +// Warning 7325: (106-108): Type struct C.P[101] 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 in small quantities per transaction. +// Warning 7325: (171-173): Type struct C.S1 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 in small quantities per transaction. +// Warning 7325: (171-173): Type struct C.P[102] 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 in small quantities per transaction. +// Warning 7325: (341-343): Type struct C.P[103] 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 in small quantities per transaction. +// Warning 7325: (341-343): Type struct C.P[104] 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 in small quantities per transaction. +// Warning 7325: (505-507): Type struct C.Q0 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 in small quantities per transaction. +// Warning 7325: (505-507): Type uint256[1][][100000000000000000001] 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 in small quantities per transaction. +// Warning 7325: (505-507): Type uint256[][100000000000000000003] 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 in small quantities per transaction. +// Warning 7325: (505-507): Type uint256[100000000000000000004] 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 in small quantities per transaction. +// Warning 7325: (505-507): Type uint256[100000000000000000002] 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 in small quantities per transaction. +// Warning 7325: (576-578): Type struct C.Q1 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 in small quantities per transaction. +// Warning 7325: (576-578): Type uint256[1][][100000000000000000005] 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 in small quantities per transaction. +// Warning 7325: (647-649): Type uint256[100000000000000000006] 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 in small quantities per transaction. +// Warning 7325: (715-717): Type struct C.Q3 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 in small quantities per transaction. +// Warning 7325: (715-717): Type uint256[][100000000000000000007] 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 in small quantities per transaction. +// Warning 7325: (783-785): Type uint256[100000000000000000008] 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 in small quantities per transaction. diff --git a/test/libsolidity/syntaxTests/largeTypes/oversized_array.sol b/test/libsolidity/syntaxTests/largeTypes/oversized_array.sol index 123773403..4bf6c86be 100644 --- a/test/libsolidity/syntaxTests/largeTypes/oversized_array.sol +++ b/test/libsolidity/syntaxTests/largeTypes/oversized_array.sol @@ -4,5 +4,5 @@ contract C { uint[2**255][2] a; } // ---- -// TypeError 7676: (60-97): Contract too large for storage. +// TypeError 7676: (60-97): Contract requires too much storage. // TypeError 1534: (77-94): Type too large for storage. diff --git a/test/libsolidity/syntaxTests/largeTypes/oversized_contract.sol b/test/libsolidity/syntaxTests/largeTypes/oversized_contract.sol index 44c7274e6..f6c82a823 100644 --- a/test/libsolidity/syntaxTests/largeTypes/oversized_contract.sol +++ b/test/libsolidity/syntaxTests/largeTypes/oversized_contract.sol @@ -5,6 +5,4 @@ contract C { uint[2**255] b; } // ---- -// TypeError 7676: (60-114): Contract too large for storage. -// Warning 3408: (77-91): Variable "a" 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 in small quantities per transaction. -// Warning 3408: (97-111): Variable "b" 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 in small quantities per transaction. +// TypeError 7676: (60-114): Contract requires too much storage. diff --git a/test/libsolidity/syntaxTests/largeTypes/oversized_contract_inheritance.sol b/test/libsolidity/syntaxTests/largeTypes/oversized_contract_inheritance.sol index 24073d4c0..a181e3a58 100644 --- a/test/libsolidity/syntaxTests/largeTypes/oversized_contract_inheritance.sol +++ b/test/libsolidity/syntaxTests/largeTypes/oversized_contract_inheritance.sol @@ -7,6 +7,4 @@ contract D is C { uint[2**255] b; } // ---- -// TypeError 7676: (95-134): Contract too large for storage. -// Warning 3408: (77-91): Variable "a" 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 in small quantities per transaction. -// Warning 3408: (117-131): Variable "b" 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 in small quantities per transaction. +// TypeError 7676: (95-134): Contract requires too much storage. diff --git a/test/libsolidity/syntaxTests/largeTypes/oversized_struct.sol b/test/libsolidity/syntaxTests/largeTypes/oversized_struct.sol index 757ec9e4a..d1c818756 100644 --- a/test/libsolidity/syntaxTests/largeTypes/oversized_struct.sol +++ b/test/libsolidity/syntaxTests/largeTypes/oversized_struct.sol @@ -8,5 +8,5 @@ contract C { S s; } // ---- -// TypeError 7676: (60-152): Contract too large for storage. +// TypeError 7676: (60-152): Contract requires too much storage. // TypeError 1534: (146-149): Type too large for storage. diff --git a/test/libsolidity/syntaxTests/largeTypes/storage_parameter.sol b/test/libsolidity/syntaxTests/largeTypes/storage_parameter.sol index 902ad73bc..836a49b03 100644 --- a/test/libsolidity/syntaxTests/largeTypes/storage_parameter.sol +++ b/test/libsolidity/syntaxTests/largeTypes/storage_parameter.sol @@ -3,4 +3,5 @@ contract C { function f(S storage) internal {} } // ---- -// Warning 2332: (64-65): Type "struct C.S" 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 in small quantities per transaction. +// Warning 7325: (64-65): Type struct C.S 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 in small quantities per transaction. +// Warning 7325: (64-65): Type uint256[57896044618658097711785492504343953926634992332820282019728792003956564819968] 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 in small quantities per transaction. diff --git a/test/libsolidity/syntaxTests/multiSource/alias_shadows_another_alias.sol b/test/libsolidity/syntaxTests/multiSource/alias_shadows_another_alias.sol new file mode 100644 index 000000000..55a7c29a6 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/alias_shadows_another_alias.sol @@ -0,0 +1,19 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +function g() pure returns (uint) { return 42; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +==== Source: s3.sol ==== +// imports f()->1337 as g() +import "s2.sol"; +// imports f()->1337 as f() and +// g()->42 as g +import {f as f, g as g} from "s1.sol"; +contract C { + function foo() public pure returns (uint) { + // calls f()->1337 / f()->1337 + return f() / g(); + } +} +// ---- +// DeclarationError 1686: (s1.sol:0-49): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/alias_shadows_function.sol b/test/libsolidity/syntaxTests/multiSource/alias_shadows_function.sol new file mode 100644 index 000000000..d59e9d3d7 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/alias_shadows_function.sol @@ -0,0 +1,19 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +function g() pure returns (uint) { return 42; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +==== Source: s3.sol ==== +// imports f()->1337 as g() +import "s2.sol"; +// imports f()->1337 as f() and +// g()->42 as g +import "s1.sol"; +contract C { + function foo() public pure returns (uint) { + // calls f()->1337 / f()->1337 + return f() / g(); + } +} +// ---- +// DeclarationError 1686: (s1.sol:0-49): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/circular_import.sol b/test/libsolidity/syntaxTests/multiSource/circular_import.sol new file mode 100644 index 000000000..b853e211b --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/circular_import.sol @@ -0,0 +1,6 @@ +==== Source: s1.sol ==== +import {f as g} from "s2.sol"; +function f() pure returns (uint) { return 1; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +function f() pure returns (uint) { return 2; } diff --git a/test/libsolidity/syntaxTests/multiSource/circular_import_2.sol b/test/libsolidity/syntaxTests/multiSource/circular_import_2.sol new file mode 100644 index 000000000..63b75aa4a --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/circular_import_2.sol @@ -0,0 +1,7 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } diff --git a/test/libsolidity/syntaxTests/multiSource/circular_import_3.sol b/test/libsolidity/syntaxTests/multiSource/circular_import_3.sol new file mode 100644 index 000000000..2a8e7a47a --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/circular_import_3.sol @@ -0,0 +1,14 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } +==== Source: s3.sol ==== +import "s1.sol"; +import "s2.sol"; +// ---- +// DeclarationError 1686: (s1.sol:39-93): Function with same name and parameter types defined twice. +// DeclarationError 1686: (s2.sol:31-77): Function with same name and parameter types defined twice. +// DeclarationError 1686: (s2.sol:78-124): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/circular_import_4.sol b/test/libsolidity/syntaxTests/multiSource/circular_import_4.sol new file mode 100644 index 000000000..88bbcb6c0 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/circular_import_4.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } +==== Source: s3.sol ==== +import "s1.sol"; diff --git a/test/libsolidity/syntaxTests/multiSource/circular_import_5.sol b/test/libsolidity/syntaxTests/multiSource/circular_import_5.sol new file mode 100644 index 000000000..5cd3e9884 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/circular_import_5.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +import {f as g, g as h} from "s2.sol"; +function f() pure returns (uint) { return h() - g(); } +==== Source: s2.sol ==== +import {f as h} from "s1.sol"; +function f() pure returns (uint) { return 2; } +function g() pure returns (uint) { return 4; } +==== Source: s3.sol ==== +import "s2.sol"; diff --git a/test/libsolidity/syntaxTests/multiSource/duplicate_import_statement.sol b/test/libsolidity/syntaxTests/multiSource/duplicate_import_statement.sol new file mode 100644 index 000000000..948cc2bec --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/duplicate_import_statement.sol @@ -0,0 +1,10 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import {f as f} from "s1.sol"; +import {f as f} from "s1.sol"; +contract C { + function g() public pure returns (uint) { + return f(); + } +} diff --git a/test/libsolidity/syntaxTests/multiSource/free_different_interger_types.sol b/test/libsolidity/syntaxTests/multiSource/free_different_interger_types.sol new file mode 100644 index 000000000..a8f47c966 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/free_different_interger_types.sol @@ -0,0 +1,10 @@ +==== Source: s1.sol ==== +function f(uint) pure returns (uint) { return 24; } +function g() pure returns (bool) { return true; } +==== Source: s2.sol ==== +import {f as g, g as g} from "s1.sol"; +contract C { + function foo() public pure returns (uint, bool) { + return (g(2), g()); + } +} diff --git a/test/libsolidity/syntaxTests/multiSource/free_function_alias_different_parameter_types.sol b/test/libsolidity/syntaxTests/multiSource/free_function_alias_different_parameter_types.sol new file mode 100644 index 000000000..2ff23c6bd --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/free_function_alias_different_parameter_types.sol @@ -0,0 +1,19 @@ +==== Source: s1.sol ==== +function f() pure returns (uint16) { return 1337; } +function g() pure returns (uint8) { return 42; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +==== Source: s3.sol ==== +// imports f(uint16)->1337 as g(uint16) +import "s2.sol"; +// imports f(uint16)->1337 as f(uint16) and +// g(uint8)->42 as g(uint8) +import {f as f, g as g} from "s1.sol"; +contract C { + function foo() public pure returns (uint) { + // calls f()->1337 / f()->1337 + return f() / g(); + } +} +// ---- +// DeclarationError 1686: (s1.sol:0-51): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/free_function_redefinition_base_derived.sol b/test/libsolidity/syntaxTests/multiSource/free_function_redefinition_base_derived.sol new file mode 100644 index 000000000..0bb58b5d0 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/free_function_redefinition_base_derived.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C {} +==== Source: s2.sol ==== +import "s1.sol"; +function f() pure returns (uint) { return 42; } +contract D is C {} +// ---- +// DeclarationError 1686: (s2.sol:17-64): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/free_function_redefinition_transitive.sol b/test/libsolidity/syntaxTests/multiSource/free_function_redefinition_transitive.sol new file mode 100644 index 000000000..944ae2163 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/free_function_redefinition_transitive.sol @@ -0,0 +1,12 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C {} +==== Source: s2.sol ==== +import "s1.sol"; +contract D is C {} +==== Source: s3.sol ==== +import "s2.sol"; +function f() pure returns (uint) { return 42; } +contract E is D {} +// ---- +// DeclarationError 1686: (s3.sol:17-64): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/free_function_resolution_override_virtual.sol b/test/libsolidity/syntaxTests/multiSource/free_function_resolution_override_virtual.sol new file mode 100644 index 000000000..a3d3ccd9e --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/free_function_resolution_override_virtual.sol @@ -0,0 +1,19 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +contract C { + function f() public pure virtual returns (uint) { + return f(); + } +} +==== Source: s2.sol ==== +import "s1.sol"; +function f() pure returns (uint) { return 42; } +contract D is C { + function f() public pure override returns (uint) { + return f(); + } +} +// ---- +// Warning 2519: (s1.sol:65-134): This declaration shadows an existing declaration. +// Warning 2519: (s2.sol:85-155): This declaration shadows an existing declaration. +// DeclarationError 1686: (s2.sol:17-64): Function with same name and parameter types defined twice. diff --git a/test/libsolidity/syntaxTests/multiSource/import_contract_function_error.sol b/test/libsolidity/syntaxTests/multiSource/import_contract_function_error.sol new file mode 100644 index 000000000..c7b5601e3 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/import_contract_function_error.sol @@ -0,0 +1,10 @@ +==== Source: s1.sol ==== +contract C { + function f() public pure returns (uint) { + return 1337; + } +} +==== Source: s2.sol ==== +import {C.f as g} from "s1.sol"; +// ---- +// ParserError 2314: (s2.sol:9-10): Expected '}' but got '.' diff --git a/test/libsolidity/syntaxTests/multiSource/imported_free_function.sol b/test/libsolidity/syntaxTests/multiSource/imported_free_function.sol new file mode 100644 index 000000000..afd511978 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/imported_free_function.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import "s1.sol"; +contract C { + function g() public pure returns (uint) { + return f(); + } +} diff --git a/test/libsolidity/syntaxTests/multiSource/multiple_imports_same_function.sol b/test/libsolidity/syntaxTests/multiSource/multiple_imports_same_function.sol new file mode 100644 index 000000000..a0dea2133 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/multiple_imports_same_function.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import {f as f, f as f, f as f} from "s1.sol"; +contract C { + function g() public pure returns (uint) { + return f(); + } +} diff --git a/test/libsolidity/syntaxTests/multiSource/reimport_imported_function.sol b/test/libsolidity/syntaxTests/multiSource/reimport_imported_function.sol new file mode 100644 index 000000000..ce29d5a55 --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/reimport_imported_function.sol @@ -0,0 +1,11 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import {f as g} from "s1.sol"; +==== Source: s3.sol ==== +import {g as h} from "s2.sol"; +contract C { + function foo() public pure returns (uint) { + return h(); + } +} diff --git a/test/libsolidity/syntaxTests/multiSource/two_imports_same_function.sol b/test/libsolidity/syntaxTests/multiSource/two_imports_same_function.sol new file mode 100644 index 000000000..0a05ea98d --- /dev/null +++ b/test/libsolidity/syntaxTests/multiSource/two_imports_same_function.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +function f() pure returns (uint) { return 1337; } +==== Source: s2.sol ==== +import {f as f, f as f} from "s1.sol"; +contract C { + function g() public pure returns (uint) { + return f(); + } +} diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/103_invalid_parameter_names_in_named_args.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/103_invalid_parameter_names_in_named_args.sol deleted file mode 100644 index b3b8c727c..000000000 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/103_invalid_parameter_names_in_named_args.sol +++ /dev/null @@ -1,11 +0,0 @@ -contract test { - function a(uint a, uint b) public returns (uint r) { - r = a + b; - } - function b() public returns (uint r) { - r = a({a: 1, c: 2}); - } -} -// ---- -// Warning 2519: (31-37): This declaration shadows an existing declaration. -// TypeError 4974: (153-168): Named argument "c" does not match function declaration. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/111_overflow_caused_by_ether_units.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/111_overflow_caused_by_ether_units.sol index e0ac9fa5d..6cdda2514 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/111_overflow_caused_by_ether_units.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/111_overflow_caused_by_ether_units.sol @@ -5,4 +5,4 @@ contract c { uint256 a; } // ---- -// TypeError 7407: (45-111): Type int_const 1157...(70 digits omitted)...0000 is not implicitly convertible to expected type uint256. +// TypeError 7407: (45-111): Type int_const 1157...(70 digits omitted)...0000 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/158_storage_variable_initialization_with_incorrect_type_int.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/158_storage_variable_initialization_with_incorrect_type_int.sol index f2c36a00a..0d0baf400 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/158_storage_variable_initialization_with_incorrect_type_int.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/158_storage_variable_initialization_with_incorrect_type_int.sol @@ -2,4 +2,4 @@ contract c { uint8 a = 1000; } // ---- -// TypeError 7407: (27-31): Type int_const 1000 is not implicitly convertible to expected type uint8. +// TypeError 7407: (27-31): Type int_const 1000 is not implicitly convertible to expected type uint8. Literal is too large to fit in uint8. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/190_negative_integers_to_signed_out_of_bound.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/190_negative_integers_to_signed_out_of_bound.sol index f56a4fcd4..a4d84f2da 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/190_negative_integers_to_signed_out_of_bound.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/190_negative_integers_to_signed_out_of_bound.sol @@ -2,4 +2,4 @@ contract test { int8 public i = -129; } // ---- -// TypeError 7407: (36-40): Type int_const -129 is not implicitly convertible to expected type int8. +// TypeError 7407: (36-40): Type int_const -129 is not implicitly convertible to expected type int8. Literal is too large to fit in int8. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/192_positive_integers_to_signed_out_of_bound.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/192_positive_integers_to_signed_out_of_bound.sol index f62c51cdf..0bc4699b3 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/192_positive_integers_to_signed_out_of_bound.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/192_positive_integers_to_signed_out_of_bound.sol @@ -2,4 +2,4 @@ contract test { int8 public j = 128; } // ---- -// TypeError 7407: (36-39): Type int_const 128 is not implicitly convertible to expected type int8. +// TypeError 7407: (36-39): Type int_const 128 is not implicitly convertible to expected type int8. Literal is too large to fit in int8. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/194_negative_integers_to_unsigned.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/194_negative_integers_to_unsigned.sol index 0d04e87ea..0dac77a73 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/194_negative_integers_to_unsigned.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/194_negative_integers_to_unsigned.sol @@ -2,4 +2,4 @@ contract test { uint8 public x = -1; } // ---- -// TypeError 7407: (37-39): Type int_const -1 is not implicitly convertible to expected type uint8. +// TypeError 7407: (37-39): Type int_const -1 is not implicitly convertible to expected type uint8. Cannot implicitly convert signed literal to unsigned type. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/195_positive_integers_to_unsigned_out_of_bound.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/195_positive_integers_to_unsigned_out_of_bound.sol index 0b5942cfb..dbc43d7dd 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/195_positive_integers_to_unsigned_out_of_bound.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/195_positive_integers_to_unsigned_out_of_bound.sol @@ -2,4 +2,4 @@ contract test { uint8 public x = 700; } // ---- -// TypeError 7407: (37-40): Type int_const 700 is not implicitly convertible to expected type uint8. +// TypeError 7407: (37-40): Type int_const 700 is not implicitly convertible to expected type uint8. Literal is too large to fit in uint8. diff --git a/test/libsolidity/syntaxTests/parsing/max_depth_reached_1.sol b/test/libsolidity/syntaxTests/parsing/max_depth_reached_1.sol new file mode 100644 index 000000000..b193b3c42 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/max_depth_reached_1.sol @@ -0,0 +1,8 @@ +contract C { + bytes + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ // 100*[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ + [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ [ +.... +// ---- +// ParserError 7319: (287-288): Maximum recursion depth reached during parsing. diff --git a/test/libsolidity/syntaxTests/parsing/max_depth_reached_2.sol b/test/libsolidity/syntaxTests/parsing/max_depth_reached_2.sol new file mode 100644 index 000000000..d57f24055 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/max_depth_reached_2.sol @@ -0,0 +1,11 @@ +contract C { + function f() { + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ // 100*{ + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ + {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ { +.... +// ---- +// ParserError 7319: (693-694): Maximum recursion depth reached during parsing. diff --git a/test/libsolidity/syntaxTests/parsing/max_depth_reached_3.sol b/test/libsolidity/syntaxTests/parsing/max_depth_reached_3.sol new file mode 100644 index 000000000..d5dfa4af5 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/max_depth_reached_3.sol @@ -0,0 +1,9 @@ +contract C { + function f() { + uint x = f + (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( // 100*( + (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( + (((((((((((((((((((((((((((((((((((((( ( +.... +// ---- +// ParserError 7319: (325-326): Maximum recursion depth reached during parsing. diff --git a/test/libsolidity/syntaxTests/parsing/max_depth_reached_4.sol b/test/libsolidity/syntaxTests/parsing/max_depth_reached_4.sol new file mode 100644 index 000000000..07a356f77 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/max_depth_reached_4.sol @@ -0,0 +1,31 @@ +contract C { + function f() public pure { + uint ok = 0; + uint nok = 0; + + (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( + ( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( ( + (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( + ( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( ( + (-( (-( (-( (-( (-( (-( (-( (-( ( + ok++ + ))))))))))))))))) + )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + + ( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( ( + (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( + ( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( ( + (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( (-( + ( (-( (-( (-( (-( (-( (-( (-( (-( ( + nok++ + )))))))))))))))))) + )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + + ? // enforce compilation error, otherwise chk_antlr_grammar complains that + // a grammatically correct file does not compile + } +} +// ---- +// ParserError 7319: (1305-1308): Maximum recursion depth reached during parsing. diff --git a/test/libsolidity/syntaxTests/scoping/name_pseudo_shadowing.sol b/test/libsolidity/syntaxTests/scoping/name_pseudo_shadowing.sol new file mode 100644 index 000000000..d2a191eeb --- /dev/null +++ b/test/libsolidity/syntaxTests/scoping/name_pseudo_shadowing.sol @@ -0,0 +1,6 @@ +contract test { + function e() external { } + function f() public pure { uint e; e = 0; } +} +// ---- +// Warning 8760: (77-83): This declaration has the same name as another declaration. diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing2.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing2.sol new file mode 100644 index 000000000..b78184109 --- /dev/null +++ b/test/libsolidity/syntaxTests/scoping/name_shadowing2.sol @@ -0,0 +1,6 @@ +function e() {} +contract test { + function f() pure public { uint e; e = 0; } +} +// ---- +// Warning 2519: (63-69): This declaration shadows an existing declaration. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abi_encodePacked_nested_dynamic_array.sol b/test/libsolidity/syntaxTests/specialFunctions/abi_encodePacked_nested_dynamic_array.sol new file mode 100644 index 000000000..3645cf592 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abi_encodePacked_nested_dynamic_array.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + abi.encodePacked([new uint[](5), new uint[](7)]); + } +} +// ---- +// TypeError 9578: (69-99): Type not supported in packed mode. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abi_encodePacked_nested_dynamic_array_v2.sol b/test/libsolidity/syntaxTests/specialFunctions/abi_encodePacked_nested_dynamic_array_v2.sol new file mode 100644 index 000000000..54a81e839 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abi_encodePacked_nested_dynamic_array_v2.sol @@ -0,0 +1,9 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f() public pure { + abi.encodePacked([new uint[](5), new uint[](7)]); + } +} +// ---- +// TypeError 9578: (104-134): Type not supported in packed mode. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abi_encode_nested_dynamic_array.sol b/test/libsolidity/syntaxTests/specialFunctions/abi_encode_nested_dynamic_array.sol new file mode 100644 index 000000000..e4e5a85dc --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abi_encode_nested_dynamic_array.sol @@ -0,0 +1,7 @@ +contract C { + function test() public pure { + abi.encode([new uint[](5), new uint[](7)]); + } +} +// ---- +// TypeError 2056: (66-96): This type cannot be encoded. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abi_encode_nested_dynamic_array_v2.sol b/test/libsolidity/syntaxTests/specialFunctions/abi_encode_nested_dynamic_array_v2.sol new file mode 100644 index 000000000..911c7b6fd --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abi_encode_nested_dynamic_array_v2.sol @@ -0,0 +1,9 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f() public pure { + abi.encode([new uint[](5), new uint[](7)]); + } +} +// ---- +// Warning 6133: (87-129): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_nested_dynamic_array.sol b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_nested_dynamic_array.sol new file mode 100644 index 000000000..d1820aab1 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_nested_dynamic_array.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + abi.decode("1234", (uint[][3])); + } +} +// ---- +// TypeError 9611: (72-81): Decoding type uint256[] memory[3] memory not supported. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_nested_dynamic_array_v2.sol b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_nested_dynamic_array_v2.sol new file mode 100644 index 000000000..55f3b169b --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_nested_dynamic_array_v2.sol @@ -0,0 +1,9 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f() public pure { + abi.decode("1234", (uint[][3])); + } +} +// ---- +// Warning 6133: (87-118): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_struct.sol b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_struct.sol new file mode 100644 index 000000000..b8b49ccdb --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_struct.sol @@ -0,0 +1,11 @@ +struct S { + uint x; +} + +contract C { + function f() public pure { + abi.decode("1234", (S)); + } +} +// ---- +// TypeError 9611: (98-99): Decoding type struct S memory not supported. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_struct_v2.sol b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_struct_v2.sol new file mode 100644 index 000000000..80c9c527a --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_struct_v2.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +struct S { + uint x; +} + +contract C { + function f() public pure { + abi.decode("1234", (S)); + } +} +// ---- +// Warning 6133: (113-136): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/string/invalid_utf8_explicit_string.sol b/test/libsolidity/syntaxTests/string/invalid_utf8_explicit_string.sol index b9a8c5279..3ad1c4b56 100644 --- a/test/libsolidity/syntaxTests/string/invalid_utf8_explicit_string.sol +++ b/test/libsolidity/syntaxTests/string/invalid_utf8_explicit_string.sol @@ -2,4 +2,4 @@ contract C { string s = string("\xa0\x00"); } // ---- -// TypeError 9640: (28-46): Explicit type conversion not allowed from "literal_string (contains invalid UTF-8 sequence at position 0)" to "string memory". +// TypeError 9640: (28-46): Explicit type conversion not allowed from "literal_string hex"a000"" to "string memory". Contains invalid UTF-8 sequence at position 0. diff --git a/test/libsolidity/syntaxTests/string/invalid_utf8_hex_string.sol b/test/libsolidity/syntaxTests/string/invalid_utf8_hex_string.sol index d72ee5af0..a089137dc 100644 --- a/test/libsolidity/syntaxTests/string/invalid_utf8_hex_string.sol +++ b/test/libsolidity/syntaxTests/string/invalid_utf8_hex_string.sol @@ -2,4 +2,4 @@ contract C { string s = hex"a000"; } // ---- -// TypeError 7407: (28-37): Type literal_string (contains invalid UTF-8 sequence at position 0) is not implicitly convertible to expected type string storage ref. +// TypeError 7407: (28-37): Type literal_string hex"a000" is not implicitly convertible to expected type string storage ref. Contains invalid UTF-8 sequence at position 0. diff --git a/test/libsolidity/syntaxTests/string/invalid_utf8_implicit_string.sol b/test/libsolidity/syntaxTests/string/invalid_utf8_implicit_string.sol index 3cf3361f3..98d83e1d4 100644 --- a/test/libsolidity/syntaxTests/string/invalid_utf8_implicit_string.sol +++ b/test/libsolidity/syntaxTests/string/invalid_utf8_implicit_string.sol @@ -2,4 +2,4 @@ contract C { string s = "\xa0\x00"; } // ---- -// TypeError 7407: (28-38): Type literal_string (contains invalid UTF-8 sequence at position 0) is not implicitly convertible to expected type string storage ref. +// TypeError 7407: (28-38): Type literal_string hex"a000" is not implicitly convertible to expected type string storage ref. Contains invalid UTF-8 sequence at position 0. diff --git a/test/libsolidity/syntaxTests/string/invalid_utf8_sequence.sol b/test/libsolidity/syntaxTests/string/invalid_utf8_sequence.sol index f5d5077f2..f8df14ca5 100644 --- a/test/libsolidity/syntaxTests/string/invalid_utf8_sequence.sol +++ b/test/libsolidity/syntaxTests/string/invalid_utf8_sequence.sol @@ -2,5 +2,5 @@ contract C { string s = unicode"À"; } // ---- -// SyntaxError 8452: (28-38): Invalid UTF-8 sequence found -// TypeError 7407: (28-38): Type literal_string (contains invalid UTF-8 sequence at position 0) is not implicitly convertible to expected type string storage ref. +// SyntaxError 8452: (28-38): Contains invalid UTF-8 sequence at position 0. +// TypeError 7407: (28-38): Type literal_string hex"c0" is not implicitly convertible to expected type string storage ref. Contains invalid UTF-8 sequence at position 0. diff --git a/test/libsolidity/syntaxTests/string/unicode_escape_literals_invalid_codepoint.sol b/test/libsolidity/syntaxTests/string/unicode_escape_literals_invalid_codepoint.sol index 46a0de5f4..975c5ac39 100644 --- a/test/libsolidity/syntaxTests/string/unicode_escape_literals_invalid_codepoint.sol +++ b/test/libsolidity/syntaxTests/string/unicode_escape_literals_invalid_codepoint.sol @@ -4,4 +4,4 @@ contract test { } } // ---- -// TypeError 6359: (86-92): Return argument type literal_string (contains invalid UTF-8 sequence at position 0) is not implicitly convertible to expected type (type of first return variable) string memory. +// TypeError 6359: (86-92): Return argument type literal_string hex"c1" is not implicitly convertible to expected type (type of first return variable) string memory. Contains invalid UTF-8 sequence at position 0. diff --git a/test/libsolidity/syntaxTests/types/array_index_too_large.sol b/test/libsolidity/syntaxTests/types/array_index_too_large.sol index 646004800..e9a57df3f 100644 --- a/test/libsolidity/syntaxTests/types/array_index_too_large.sol +++ b/test/libsolidity/syntaxTests/types/array_index_too_large.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 7407: (140-218): Type int_const 1234...(70 digits omitted)...5678 is not implicitly convertible to expected type uint256. +// TypeError 7407: (140-218): Type int_const 1234...(70 digits omitted)...5678 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. diff --git a/test/libsolidity/syntaxTests/types/bytesXX_index_assign.sol b/test/libsolidity/syntaxTests/types/bytesNN_index_assign.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/bytesXX_index_assign.sol rename to test/libsolidity/syntaxTests/types/bytesNN_index_assign.sol diff --git a/test/libsolidity/syntaxTests/types/bytes_to_contract.sol b/test/libsolidity/syntaxTests/types/bytesNN_to_contract.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/bytes_to_contract.sol rename to test/libsolidity/syntaxTests/types/bytesNN_to_contract.sol diff --git a/test/libsolidity/syntaxTests/types/bytes_to_uint_same_size.sol b/test/libsolidity/syntaxTests/types/bytesNN_to_uint_same_size.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/bytes_to_uint_same_size.sol rename to test/libsolidity/syntaxTests/types/bytesNN_to_uint_same_size.sol diff --git a/test/libsolidity/syntaxTests/types/bytesm.sol b/test/libsolidity/syntaxTests/types/bytesNN_upcasting.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/bytesm.sol rename to test/libsolidity/syntaxTests/types/bytesNN_upcasting.sol diff --git a/test/libsolidity/syntaxTests/types/bytesNN_with_oversized_hex_string.sol b/test/libsolidity/syntaxTests/types/bytesNN_with_oversized_hex_string.sol new file mode 100644 index 000000000..9412a7882 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/bytesNN_with_oversized_hex_string.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure returns (bytes2) { + return bytes2(hex"123456"); + } +} +// ---- +// TypeError 9640: (76-95): Explicit type conversion not allowed from "literal_string hex"123456"" to "bytes2". Literal is larger than the type. diff --git a/test/libsolidity/syntaxTests/types/decimal_literal_to_bytesXX_explicit.sol b/test/libsolidity/syntaxTests/types/decimal_literal_to_bytesNN_explicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/decimal_literal_to_bytesXX_explicit.sol rename to test/libsolidity/syntaxTests/types/decimal_literal_to_bytesNN_explicit.sol diff --git a/test/libsolidity/syntaxTests/types/decimal_literal_to_bytesXX_implicit.sol b/test/libsolidity/syntaxTests/types/decimal_literal_to_bytesNN_implicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/decimal_literal_to_bytesXX_implicit.sol rename to test/libsolidity/syntaxTests/types/decimal_literal_to_bytesNN_implicit.sol diff --git a/test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_different_size_explicit.sol b/test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_different_size_explicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_different_size_explicit.sol rename to test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_different_size_explicit.sol diff --git a/test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_different_size_implicit.sol b/test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_different_size_implicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_different_size_implicit.sol rename to test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_different_size_implicit.sol diff --git a/test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_same_size_explicit.sol b/test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_same_size_explicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_same_size_explicit.sol rename to test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_same_size_explicit.sol diff --git a/test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_same_size_implicit.sol b/test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_same_size_implicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/hex_literal_to_bytesXX_same_size_implicit.sol rename to test/libsolidity/syntaxTests/types/hex_literal_to_bytesNN_same_size_implicit.sol diff --git a/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_different_size_explicit.sol b/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_different_size_explicit.sol new file mode 100644 index 000000000..18b628cb6 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_different_size_explicit.sol @@ -0,0 +1,20 @@ +contract C { + function f() public pure { + bytes1 b1 = bytes1(hex""); + bytes1 b2 = bytes1(hex"1234"); + bytes2 b3 = bytes2(hex"12"); + bytes2 b4 = bytes2(hex"1234"); + bytes2 b5 = bytes2(hex"123456"); + bytes3 b6 = bytes3(hex"1234"); + bytes3 b7 = bytes3(hex"123456"); + bytes3 b8 = bytes3(hex"12345678"); + bytes4 b9 = bytes4(hex"123456"); + bytes4 b10 = bytes4(hex"12345678"); + bytes4 b11 = bytes4(hex"1234567890"); + } +} +// ---- +// TypeError 9640: (92-109): Explicit type conversion not allowed from "literal_string hex"1234"" to "bytes1". Literal is larger than the type. +// TypeError 9640: (198-217): Explicit type conversion not allowed from "literal_string hex"123456"" to "bytes2". Literal is larger than the type. +// TypeError 9640: (310-331): Explicit type conversion not allowed from "literal_string hex"12345678"" to "bytes3". Literal is larger than the type. +// TypeError 9640: (430-453): Explicit type conversion not allowed from "literal_string hex"1234567890"" to "bytes4". Literal is larger than the type. diff --git a/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_same_size_explicit.sol b/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_same_size_explicit.sol new file mode 100644 index 000000000..e121abbd6 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_same_size_explicit.sol @@ -0,0 +1,13 @@ +contract C { + function f() public pure { + bytes1 b1 = bytes1(hex"01"); + bytes1 b2 = bytes1(hex"FF"); + bytes2 b3 = bytes2(hex"0100"); + bytes2 b4 = bytes2(hex"FFFF"); + bytes3 b5 = bytes3(hex"010000"); + bytes3 b6 = bytes3(hex"FFFFFF"); + bytes4 b7 = bytes4(hex"01000000"); + bytes4 b8 = bytes4(hex"FFFFFFFF"); + b1; b2; b3; b4; b5; b6; b7; b8; + } +} diff --git a/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_same_size_implicit.sol b/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_same_size_implicit.sol new file mode 100644 index 000000000..dbf4a4cf0 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/hex_string_to_bytesNN_same_size_implicit.sol @@ -0,0 +1,13 @@ +contract C { + function f() public pure { + bytes1 b1 = hex"01"; + bytes1 b2 = hex"FF"; + bytes2 b3 = hex"0100"; + bytes2 b4 = hex"FFFF"; + bytes3 b5 = hex"010000"; + bytes3 b6 = hex"FFFFFF"; + bytes4 b7 = hex"01000000"; + bytes4 b8 = hex"FFFFFFFF"; + b1; b2; b3; b4; b5; b6; b7; b8; + } +} diff --git a/test/libsolidity/syntaxTests/types/rational_number_array_index_limit.sol b/test/libsolidity/syntaxTests/types/rational_number_array_index_limit.sol index 9b4f05c42..f41eb8b7a 100644 --- a/test/libsolidity/syntaxTests/types/rational_number_array_index_limit.sol +++ b/test/libsolidity/syntaxTests/types/rational_number_array_index_limit.sol @@ -2,4 +2,4 @@ contract c { uint[2**253] data; } // ---- -// Warning 3408: (17-34): Variable "data" 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 in small quantities per transaction. +// Warning 7325: (17-29): Type uint256[14474011154664524427946373126085988481658748083205070504932198000989141204992] 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 in small quantities per transaction. diff --git a/test/libsolidity/syntaxTests/types/rational_number_bitshift_limit.sol b/test/libsolidity/syntaxTests/types/rational_number_bitshift_limit.sol index a397993b9..9c59b015c 100644 --- a/test/libsolidity/syntaxTests/types/rational_number_bitshift_limit.sol +++ b/test/libsolidity/syntaxTests/types/rational_number_bitshift_limit.sol @@ -7,7 +7,7 @@ contract c { } } // ---- -// TypeError 7407: (71-80): Type int_const 5221...(1225 digits omitted)...5168 is not implicitly convertible to expected type int256. +// TypeError 7407: (71-80): Type int_const 5221...(1225 digits omitted)...5168 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (133-142): Operator << not compatible with types int_const 1 and int_const 4096 // TypeError 2271: (169-182): Operator << not compatible with types int_const 1000...(1226 digits omitted)...0000 and int_const 2 -// TypeError 7407: (169-182): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (169-182): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. diff --git a/test/libsolidity/syntaxTests/types/rational_number_exp_limit_fail.sol b/test/libsolidity/syntaxTests/types/rational_number_exp_limit_fail.sol index a989c4583..39be18a28 100644 --- a/test/libsolidity/syntaxTests/types/rational_number_exp_limit_fail.sol +++ b/test/libsolidity/syntaxTests/types/rational_number_exp_limit_fail.sol @@ -20,28 +20,28 @@ contract c { } // ---- // TypeError 2271: (71-102): Operator ** not compatible with types int_const 1797...(301 digits omitted)...7216 and int_const 4. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (71-102): Type int_const 1797...(301 digits omitted)...7216 is not implicitly convertible to expected type int256. +// TypeError 7407: (71-102): Type int_const 1797...(301 digits omitted)...7216 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (116-148): Operator ** not compatible with types int_const 1797...(301 digits omitted)...7216 and int_const 4. Precision of rational constants is limited to 4096 bits. // TypeError 2271: (116-153): Operator ** not compatible with types int_const 1797...(301 digits omitted)...7216 and int_const 4. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (116-153): Type int_const 1797...(301 digits omitted)...7216 is not implicitly convertible to expected type int256. +// TypeError 7407: (116-153): Type int_const 1797...(301 digits omitted)...7216 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (167-203): Operator ** not compatible with types int_const 4 and int_const -179...(302 digits omitted)...7216 // TypeError 2271: (217-228): Operator ** not compatible with types int_const 2 and int_const 1000...(1226 digits omitted)...0000 // TypeError 2271: (242-254): Operator ** not compatible with types int_const -2 and int_const 1000...(1226 digits omitted)...0000 // TypeError 2271: (268-280): Operator ** not compatible with types int_const 2 and int_const -100...(1227 digits omitted)...0000 // TypeError 2271: (294-307): Operator ** not compatible with types int_const -2 and int_const -100...(1227 digits omitted)...0000 // TypeError 2271: (321-332): Operator ** not compatible with types int_const 1000...(1226 digits omitted)...0000 and int_const 2. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (321-332): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (321-332): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (346-358): Operator ** not compatible with types int_const -100...(1227 digits omitted)...0000 and int_const 2. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (346-358): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (346-358): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (372-384): Operator ** not compatible with types int_const 1000...(1226 digits omitted)...0000 and int_const -2. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (372-384): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (372-384): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (398-411): Operator ** not compatible with types int_const -100...(1227 digits omitted)...0000 and int_const -2. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (398-411): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (398-411): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (425-441): Operator ** not compatible with types int_const 1000...(1226 digits omitted)...0000 and int_const 1000...(1226 digits omitted)...0000 -// TypeError 7407: (425-441): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (425-441): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (455-472): Operator ** not compatible with types int_const 1000...(1226 digits omitted)...0000 and int_const -100...(1227 digits omitted)...0000 -// TypeError 7407: (455-472): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (455-472): Type int_const 1000...(1226 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (486-503): Operator ** not compatible with types int_const -100...(1227 digits omitted)...0000 and int_const 1000...(1226 digits omitted)...0000 -// TypeError 7407: (486-503): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (486-503): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. // TypeError 2271: (517-535): Operator ** not compatible with types int_const -100...(1227 digits omitted)...0000 and int_const -100...(1227 digits omitted)...0000 -// TypeError 7407: (517-535): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. +// TypeError 7407: (517-535): Type int_const -100...(1227 digits omitted)...0000 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. diff --git a/test/libsolidity/syntaxTests/types/rational_number_huge_fail.sol b/test/libsolidity/syntaxTests/types/rational_number_huge_fail.sol index 1e3239ddf..cec814ef3 100644 --- a/test/libsolidity/syntaxTests/types/rational_number_huge_fail.sol +++ b/test/libsolidity/syntaxTests/types/rational_number_huge_fail.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 7407: (142-209): Type int_const 1852...(71 digits omitted)...7281 is not implicitly convertible to expected type uint256. +// TypeError 7407: (142-209): Type int_const 1852...(71 digits omitted)...7281 is not implicitly convertible to expected type uint256. Literal is too large to fit in uint256. diff --git a/test/libsolidity/syntaxTests/types/rational_number_mul_limit.sol b/test/libsolidity/syntaxTests/types/rational_number_mul_limit.sol index c2d94da36..a02578453 100644 --- a/test/libsolidity/syntaxTests/types/rational_number_mul_limit.sol +++ b/test/libsolidity/syntaxTests/types/rational_number_mul_limit.sol @@ -6,4 +6,4 @@ contract c { } // ---- // TypeError 2271: (71-90): Operator * not compatible with types int_const 5221...(1225 digits omitted)...5168 and int_const 5221...(1225 digits omitted)...5168. Precision of rational constants is limited to 4096 bits. -// TypeError 7407: (71-90): Type int_const 5221...(1225 digits omitted)...5168 is not implicitly convertible to expected type int256. +// TypeError 7407: (71-90): Type int_const 5221...(1225 digits omitted)...5168 is not implicitly convertible to expected type int256. Literal is too large to fit in int256. diff --git a/test/libsolidity/syntaxTests/types/zero_literal_to_bytesXX_explicit.sol b/test/libsolidity/syntaxTests/types/zero_literal_to_bytesNN_explicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/zero_literal_to_bytesXX_explicit.sol rename to test/libsolidity/syntaxTests/types/zero_literal_to_bytesNN_explicit.sol diff --git a/test/libsolidity/syntaxTests/types/zero_literal_to_bytesXX_implicit.sol b/test/libsolidity/syntaxTests/types/zero_literal_to_bytesNN_implicit.sol similarity index 100% rename from test/libsolidity/syntaxTests/types/zero_literal_to_bytesXX_implicit.sol rename to test/libsolidity/syntaxTests/types/zero_literal_to_bytesNN_implicit.sol diff --git a/test/libsolidity/util/ContractABIUtils.cpp b/test/libsolidity/util/ContractABIUtils.cpp index a3a19e6e5..e3ab01128 100644 --- a/test/libsolidity/util/ContractABIUtils.cpp +++ b/test/libsolidity/util/ContractABIUtils.cpp @@ -319,8 +319,11 @@ solidity::frontend::test::ParameterList ContractABIUtils::failureParameters(byte ParameterList parameters; parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::HexString, ABIType::AlignNone, 4}, FormatInfo{}}); - parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}}); - parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}}); + if (_bytes.size() > 4) + { + parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}}); + parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}}); + } /// If _bytes contains at least a 1 byte message (function selector + tail pointer + message length + message) /// append an additional string parameter to represent that message. diff --git a/test/libyul/CompilabilityChecker.cpp b/test/libyul/CompilabilityChecker.cpp index ad1a6fd5e..e8890a8bb 100644 --- a/test/libyul/CompilabilityChecker.cpp +++ b/test/libyul/CompilabilityChecker.cpp @@ -39,7 +39,7 @@ string check(string const& _input) Object obj; std::tie(obj.code, obj.analysisInfo) = yul::test::parse(_input, false); BOOST_REQUIRE(obj.code); - map functions = CompilabilityChecker::run(EVMDialect::strictAssemblyForEVM(solidity::test::CommonOptions::get().evmVersion()), obj, true); + auto functions = CompilabilityChecker(EVMDialect::strictAssemblyForEVM(solidity::test::CommonOptions::get().evmVersion()), obj, true).stackDeficit; string out; for (auto const& function: functions) out += function.first.str() + ": " + to_string(function.second) + " "; diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 7b8e56119..d232d5705 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -126,149 +126,6 @@ do \ BOOST_AUTO_TEST_SUITE(YulParser) -BOOST_AUTO_TEST_CASE(smoke_test) -{ - BOOST_CHECK(successParse("{ }")); -} - -BOOST_AUTO_TEST_CASE(vardecl) -{ - BOOST_CHECK(successParse("{ let x:u256 := 7:u256 }")); -} - -BOOST_AUTO_TEST_CASE(vardecl_bool) -{ - BOOST_CHECK(successParse("{ let x:bool := true:bool }")); - BOOST_CHECK(successParse("{ let x:bool := false:bool }")); -} - -BOOST_AUTO_TEST_CASE(vardecl_empty) -{ - BOOST_CHECK(successParse("{ let x:u256 }")); -} - -BOOST_AUTO_TEST_CASE(assignment) -{ - BOOST_CHECK(successParse("{ let x:u256 := 2:u256 let y:u256 := x }")); -} - -BOOST_AUTO_TEST_CASE(period_in_identifier) -{ - BOOST_CHECK(successParse("{ let x.y:u256 := 2:u256 }")); -} - -BOOST_AUTO_TEST_CASE(period_not_as_identifier_start) -{ - CHECK_ERROR("{ let .y:u256 }", ParserError, "Expected identifier but got '.'"); -} - -BOOST_AUTO_TEST_CASE(period_in_identifier_spaced) -{ - CHECK_ERROR("{ let x. y:u256 }", ParserError, "Call or assignment expected"); - CHECK_ERROR("{ let x .y:u256 }", ParserError, "Literal or identifier expected"); - CHECK_ERROR("{ let x . y:u256 }", ParserError, "Literal or identifier expected"); -} - -BOOST_AUTO_TEST_CASE(period_in_identifier_start) -{ - BOOST_CHECK(successParse("{ x.y(2:u256) function x.y(a:u256) {} }")); -} - -BOOST_AUTO_TEST_CASE(period_in_identifier_start_with_comment) -{ - BOOST_CHECK(successParse("/// comment\n{ x.y(2:u256) function x.y(a:u256) {} }")); -} - -BOOST_AUTO_TEST_CASE(vardecl_complex) -{ - BOOST_CHECK(successParse("{ function add(a:u256, b:u256) -> c:u256 {} let y:u256 := 2:u256 let x:u256 := add(7:u256, add(6:u256, y)) }")); -} - -BOOST_AUTO_TEST_CASE(blocks) -{ - BOOST_CHECK(successParse("{ let x:u256 := 7:u256 { let y:u256 := 3:u256 } { let z:u256 := 2:u256 } }")); -} - -BOOST_AUTO_TEST_CASE(function_definitions) -{ - BOOST_CHECK(successParse("{ function f() { } function g(a:u256) -> x:u256 { } }")); -} - -BOOST_AUTO_TEST_CASE(function_definitions_multiple_args) -{ - BOOST_CHECK(successParse("{ function f(a:u256, d:u256) { } function g(a:u256, d:u256) -> x:u256, y:u256 { } }")); -} - -BOOST_AUTO_TEST_CASE(function_calls) -{ - BOOST_CHECK(successParse("{ function f(a:u256) -> b:u256 {} function g(a:u256, b:u256, c:u256) {} function x() { g(1:u256, 2:u256, f(3:u256)) x() } }")); -} - -BOOST_AUTO_TEST_CASE(tuple_assignment) -{ - BOOST_CHECK(successParse("{ function f() -> a:u256, b:u256, c:u256 {} let x:u256, y:u256, z:u256 := f() }")); -} - -BOOST_AUTO_TEST_CASE(instructions) -{ - CHECK_ERROR("{ pop }", ParserError, "Call or assignment expected."); -} - -BOOST_AUTO_TEST_CASE(push) -{ - CHECK_ERROR("{ 0x42:u256 }", ParserError, "Call or assignment expected."); -} - -BOOST_AUTO_TEST_CASE(assign_from_stack) -{ - CHECK_ERROR("{ =: x:u256 }", ParserError, "Literal or identifier expected."); -} - -BOOST_AUTO_TEST_CASE(empty_call) -{ - CHECK_ERROR("{ () }", ParserError, "Literal or identifier expected."); -} - -BOOST_AUTO_TEST_CASE(tokens_as_identifers) -{ - BOOST_CHECK(successParse("{ let return:u256 := 1:u256 }")); - BOOST_CHECK(successParse("{ let byte:u256 := 1:u256 }")); - BOOST_CHECK(successParse("{ let address:u256 := 1:u256 }")); - BOOST_CHECK(successParse("{ let bool:u256 := 1:u256 }")); -} - -BOOST_AUTO_TEST_CASE(optional_types) -{ - BOOST_CHECK(successParse("{ let x := 1:u256 }")); - BOOST_CHECK(successParse("{ let x:u256 := 1 }")); - BOOST_CHECK(successParse("{ function f(a) {} }")); - BOOST_CHECK(successParse("{ function f(a:u256) -> b {} }")); -} - -BOOST_AUTO_TEST_CASE(number_literals) -{ - BOOST_CHECK(successParse("{ let x:u256 := 1:u256 }")); - CHECK_ERROR("{ let x:u256 := .1:u256 }", ParserError, "Invalid number literal."); - CHECK_ERROR("{ let x:u256 := 1e5:u256 }", ParserError, "Invalid number literal."); - CHECK_ERROR("{ let x:u256 := 67.235:u256 }", ParserError, "Invalid number literal."); - CHECK_ERROR("{ let x:u256 := 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:u256 }", TypeError, "Number literal too large (> 256 bits)"); -} - -BOOST_AUTO_TEST_CASE(builtin_types) -{ - BOOST_CHECK(successParse("{ let x:bool := true:bool }")); - BOOST_CHECK(successParse("{ let x:u8 := 1:u8 }")); - BOOST_CHECK(successParse("{ let x:s8 := 1:s8 }")); - BOOST_CHECK(successParse("{ let x:u32 := 1:u32 }")); - BOOST_CHECK(successParse("{ let x:s32 := 1:s32 }")); - BOOST_CHECK(successParse("{ let x:u64 := 1:u64 }")); - BOOST_CHECK(successParse("{ let x:s64 := 1:s64 }")); - BOOST_CHECK(successParse("{ let x:u128 := 1:u128 }")); - BOOST_CHECK(successParse("{ let x:s128 := 1:s128 }")); - BOOST_CHECK(successParse("{ let x:u256 := 1:u256 }")); - BOOST_CHECK(successParse("{ let x:s256 := 1:s256 }")); -} - BOOST_AUTO_TEST_CASE(recursion_depth) { string input; diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 13c9ed5c7..e61b5d2d8 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -46,18 +46,22 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -68,6 +72,7 @@ #include #include #include +#include #include #include @@ -101,6 +106,12 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename): BOOST_THROW_EXCEPTION(runtime_error("Filename path has to contain a directory: \"" + _filename + "\".")); m_optimizerStep = std::prev(std::prev(path.end()))->string(); + if (m_optimizerStep == "reasoningBasedSimplifier" && ( + solidity::test::CommonOptions::get().disableSMT || + ReasoningBasedSimplifier::invalidInCurrentEnvironment() + )) + m_shouldRun = false; + m_source = m_reader.source(); auto dialectName = m_reader.stringSetting("dialect", "evm"); @@ -224,9 +235,14 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line else if (m_optimizerStep == "expressionSimplifier") { disambiguate(); + ExpressionSplitter::run(*m_context, *m_object->code); + CommonSubexpressionEliminator::run(*m_context, *m_object->code); ExpressionSimplifier::run(*m_context, *m_object->code); ExpressionSimplifier::run(*m_context, *m_object->code); ExpressionSimplifier::run(*m_context, *m_object->code); + UnusedPruner::run(*m_context, *m_object->code); + ExpressionJoiner::run(*m_context, *m_object->code); + ExpressionJoiner::run(*m_context, *m_object->code); } else if (m_optimizerStep == "fullSimplify") { @@ -241,6 +257,13 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line ExpressionJoiner::run(*m_context, *m_object->code); ExpressionJoiner::run(*m_context, *m_object->code); } + else if (m_optimizerStep == "unusedFunctionParameterPruner") + { + disambiguate(); + FunctionHoister::run(*m_context, *m_object->code); + LiteralRematerialiser::run(*m_context, *m_object->code); + UnusedFunctionParameterPruner::run(*m_context, *m_object->code); + } else if (m_optimizerStep == "unusedPruner") { disambiguate(); @@ -307,6 +330,11 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line LiteralRematerialiser::run(*m_context, *m_object->code); StructuralSimplifier::run(*m_context, *m_object->code); } + else if (m_optimizerStep == "reasoningBasedSimplifier") + { + disambiguate(); + ReasoningBasedSimplifier::run(*m_context, *m_object->code); + } else if (m_optimizerStep == "equivalentFunctionCombiner") { disambiguate(); @@ -353,6 +381,58 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line obj.analysisInfo = m_analysisInfo; OptimiserSuite::run(*m_dialect, &meter, obj, true, solidity::frontend::OptimiserSettings::DefaultYulOptimiserSteps); } + else if (m_optimizerStep == "stackLimitEvader") + { + yul::Object obj; + obj.code = m_object->code; + obj.analysisInfo = m_analysisInfo; + disambiguate(); + StackLimitEvader::run(*m_context, obj, CompilabilityChecker{ + *m_dialect, + obj, + true + }.unreachableVariables); + } + else if (m_optimizerStep == "fakeStackLimitEvader") + { + yul::Object obj; + obj.code = m_object->code; + obj.analysisInfo = m_analysisInfo; + disambiguate(); + // Mark all variables with a name starting with "$" for escalation to memory. + struct FakeUnreachableGenerator: ASTWalker + { + map> fakeUnreachables; + using ASTWalker::operator(); + void operator()(FunctionDefinition const& _function) override + { + YulString originalFunctionName = m_currentFunction; + m_currentFunction = _function.name; + ASTWalker::operator()(_function); + m_currentFunction = originalFunctionName; + } + void visitVariableName(YulString _var) + { + if (!_var.empty() && _var.str().front() == '$') + fakeUnreachables[m_currentFunction].insert(_var); + } + void operator()(VariableDeclaration const& _varDecl) override + { + for (auto const& var: _varDecl.variables) + visitVariableName(var.name); + ASTWalker::operator()(_varDecl); + } + void operator()(Identifier const& _identifier) override + { + visitVariableName(_identifier.name); + ASTWalker::operator()(_identifier); + } + YulString m_currentFunction = YulString{}; + }; + FakeUnreachableGenerator fakeUnreachableGenerator; + fakeUnreachableGenerator(*obj.code); + StackLimitEvader::run(*m_context, obj, fakeUnreachableGenerator.fakeUnreachables); + } else { AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << endl; diff --git a/test/libyul/ewasmTranslationTests/memoryguard.yul b/test/libyul/ewasmTranslationTests/memoryguard.yul new file mode 100644 index 000000000..5aafc88d2 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/memoryguard.yul @@ -0,0 +1,12 @@ +{ + mstore(0x40, memoryguard(0x0102030405060708)) + sstore(1, mload(0x40)) +} +// ---- +// Trace: +// Memory dump: +// 0: 0000000000000000000000000000000000000000000000000000000000000001 +// 20: 0000000000000000000000000000000000000000000000000102030405060708 +// 80: 0000000000000000000000000000000000000000000000000102030405060708 +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000102030405060708 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul index 783319395..595b9c792 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul @@ -2,6 +2,7 @@ function f() -> x, z {} let c, d := f() let y := add(d, add(c, 7)) + sstore(y, 20) } // ---- // step: expressionSimplifier @@ -10,5 +11,5 @@ // function f() -> x, z // { } // let c, d := f() -// let y := add(add(d, c), 7) +// sstore(add(add(d, c), 7), 20) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul index d465600e3..7288ef56f 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul @@ -1,7 +1,11 @@ { + // This is not fully simplified on purpose because we + // need another split step in between. The full simplification + // is tested in the fullSuite. let x := calldataload(0) let a := and(0xff, shr(248, shl(248, shr(248, x)))) let b := shr(12, shl(8, and(x, 0xf0f0))) + sstore(a, b) } // ==== // EVMVersion: >byzantium @@ -10,6 +14,6 @@ // // { // let x := calldataload(0) -// let a := shr(248, x) -// let b := and(shr(4, x), 3855) +// let a := and(0xff, and(shr(248, x), 255)) +// sstore(a, shr(12, and(shl(8, x), 15790080))) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul index 6649a86b5..f57a5108b 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul @@ -1,4 +1,7 @@ { + // This is not fully simplified on purpose because we + // need another split step in between. The full simplification + // is tested in the fullSuite. let x := calldataload(0) let a := and(0xff, shr(248, shl(248, shr(248, and(x, 0xf))))) let b := shl(12, shr(4, and(x, 0xf0f0))) @@ -7,6 +10,13 @@ let e := shl(255, shr(4, and(0xf0f0, x))) let f := shl(12, shr(256, and(0xf0f0, x))) let g := shl(256, shr(4, and(0xf0f0, x))) + sstore(10, a) + sstore(11, b) + sstore(12, c) + sstore(13, d) + sstore(14, e) + sstore(15, f) + sstore(16, g) } // ==== // EVMVersion: >byzantium @@ -15,11 +25,24 @@ // // { // let x := calldataload(0) -// let a := 0 -// let b := and(shl(8, x), 15790080) -// let c := and(shl(8, x), 15790080) -// let d := 0 -// let e := and(shl(251, x), 0x8000000000000000000000000000000000000000000000000000000000000000) +// let _2 := 0xf +// let _5 := and(shr(248, x), 0) +// let _10 := 0xff +// let a := and(_5, 255) +// let _14 := and(shr(4, x), 3855) +// let _15 := 12 +// let b := shl(_15, _14) +// let _19 := and(shr(4, x), 3855) +// let c := shl(_15, _19) +// let d := shl(_15, and(shr(255, x), 0)) +// let e := shl(_10, _19) // let f := 0 // let g := 0 +// sstore(10, a) +// sstore(11, b) +// sstore(_15, c) +// sstore(13, d) +// sstore(14, e) +// sstore(_2, f) +// sstore(16, g) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul index 4211b6afe..14ff1b375 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul @@ -1,10 +1,19 @@ { + // This is not fully simplified on purpose because we + // need another split step in between. The full simplification + // is tested in the fullSuite. let x := calldataload(0) let a := shl(12, shr(4, x)) let b := shl(4, shr(12, x)) let c := shr(12, shl(4, x)) let d := shr(4, shl(12, x)) let e := shl(150, shr(2, shl(150, x))) + sstore(15, x) + sstore(16, a) + sstore(17, b) + sstore(18, c) + sstore(19, d) + sstore(20, e) } // ==== // EVMVersion: >byzantium @@ -17,5 +26,12 @@ // let b := and(shr(8, x), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0) // let c := and(shr(8, x), 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) // let d := and(shl(8, x), 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00) -// let e := 0 +// let _14 := 150 +// let e := shl(_14, and(shl(148, x), 0x3ffffffffffffffffffffffffff0000000000000000000000000000000000000)) +// sstore(15, x) +// sstore(16, a) +// sstore(17, b) +// sstore(18, c) +// sstore(19, d) +// sstore(20, e) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul index 2f655efba..56d18fb7b 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul @@ -1,5 +1,8 @@ -{ let a := add(7, sub(mload(0), 7)) } +{ + let a := add(7, sub(mload(0), 7)) + mstore(20, a) +} // ---- // step: expressionSimplifier // -// { let a := mload(0) } +// { mstore(20, mload(0)) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul index 8bf04b987..ce2949993 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul @@ -1,5 +1,8 @@ -{ let a := add(1, mul(3, 4)) } +{ + let a := add(1, mul(3, 4)) + sstore(7, a) +} // ---- // step: expressionSimplifier // -// { let a := 13 } +// { sstore(7, 13) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul index bbda84653..8a5265992 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul @@ -1,6 +1,10 @@ { + // This is not fully simplified on purpose because we + // need another split step in between. The full simplification + // is tested in the fullSuite. let a := and(create2(0, 0, 0x20, 0), 0xffffffffffffffffffffffffffffffffffffffff) let b := and(0xffffffffffffffffffffffffffffffffffffffff, create2(0, 0, 0x20, 0)) + sstore(a, b) } // ==== // EVMVersion: >=constantinople @@ -8,6 +12,9 @@ // step: expressionSimplifier // // { -// let a := create2(0, 0, 0x20, 0) -// let b := create2(0, 0, 0x20, 0) +// let _1 := 0xffffffffffffffffffffffffffffffffffffffff +// let _2 := 0 +// let _3 := 0x20 +// let a := and(create2(_2, _2, _3, _2), _1) +// sstore(a, and(_1, create2(_2, _2, _3, _2))) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul index 44a8cabb0..8e77b8726 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul @@ -1,11 +1,20 @@ { - let a := and(create(0, 0, 0x20), 0xffffffffffffffffffffffffffffffffffffffff) + // This is not fully simplified on purpose because we + // need another split step in between. The full simplification + // is tested in the fullSuite. + let c := create(0, 0, 0x20) + let a := and(c, 0xffffffffffffffffffffffffffffffffffffffff) let b := and(0xffffffffffffffffffffffffffffffffffffffff, create(0, 0, 0x20)) + sstore(a, b) } // ---- // step: expressionSimplifier // // { -// let a := create(0, 0, 0x20) -// let b := create(0, 0, 0x20) +// let _1 := 0x20 +// let _2 := 0 +// let c := create(_2, _2, _1) +// let _4 := 0xffffffffffffffffffffffffffffffffffffffff +// let a := and(c, _4) +// sstore(a, and(_4, create(_2, _2, _1))) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/exp_simplifications.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/exp_simplifications.yul new file mode 100644 index 000000000..879b05883 --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/exp_simplifications.yul @@ -0,0 +1,22 @@ +{ + let t := calldataload(0) + sstore(0, exp(0, t)) + sstore(1, exp(1, t)) + sstore(2, exp(2, t)) + // The following should not be simplified + sstore(3, exp(8, t)) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: expressionSimplifier +// +// { +// let _1 := 0 +// let t := calldataload(_1) +// sstore(_1, iszero(t)) +// sstore(1, 1) +// let _8 := 2 +// sstore(_8, shl(t, 1)) +// sstore(3, exp(8, t)) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/idempotency.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/idempotency.yul index 78d51db73..9698dfdff 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/idempotency.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/idempotency.yul @@ -3,6 +3,7 @@ let z := calldataload(1) let t := and(and(x, z), x) let w := or(or(x, z), x) + sstore(t, w) } // ---- // step: expressionSimplifier @@ -11,5 +12,5 @@ // let x := calldataload(0) // let z := calldataload(1) // let t := and(x, z) -// let w := or(x, z) +// sstore(t, or(x, z)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul index 38502d22c..6bb6a751b 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul @@ -1,5 +1,8 @@ -{ let a := sub(calldataload(0), calldataload(0)) } +{ + let a := sub(calldataload(0), calldataload(0)) + sstore(0, a) +} // ---- // step: expressionSimplifier // -// { let a := 0 } +// { sstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul index 5f3d268ca..686ae2b63 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul @@ -1,7 +1,11 @@ -{ let a := sub(calldataload(1), calldataload(0)) } +{ + let a := sub(calldataload(1), calldataload(0)) + sstore(0, a) +} // ---- // step: expressionSimplifier // // { -// let a := sub(calldataload(1), calldataload(0)) +// let _1 := 0 +// sstore(_1, sub(calldataload(1), calldataload(_1))) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul index d75ceb831..57d84ae15 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul @@ -1,11 +1,9 @@ { let a := mload(0) let b := sub(a, a) + sstore(0, b) } // ---- // step: expressionSimplifier // -// { -// let a := mload(0) -// let b := 0 -// } +// { sstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul index 73b6bfa54..a035494b8 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul @@ -1,6 +1,7 @@ { function f() -> a {} let b := add(7, sub(f(), 7)) + sstore(0, b) } // ---- // step: expressionSimplifier @@ -8,5 +9,5 @@ // { // function f() -> a // { } -// let b := f() +// sstore(0, f()) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul index fc75f131f..d7da5e41f 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul @@ -1,11 +1,9 @@ { let a := mload(sub(7, 7)) let b := sub(a, 0) + sstore(0, b) } // ---- // step: expressionSimplifier // -// { -// let a := mload(0) -// let b := a -// } +// { sstore(0, mload(0)) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul index 073db8d4e..22bfaf91f 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul @@ -4,13 +4,23 @@ let c := byte(20, a) // create cannot be removed. let d := byte(33, create(0, 0, 0x20)) + sstore(7, a) + sstore(8, b) + sstore(9, c) + sstore(10, d) } // ---- // step: expressionSimplifier // // { -// let a := calldataload(0) +// let _1 := 0 +// let a := calldataload(_1) // let b := 0 // let c := byte(20, a) -// let d := byte(33, create(0, 0, 0x20)) +// pop(create(_1, _1, 0x20)) +// let d := 0 +// sstore(7, a) +// sstore(8, b) +// sstore(9, c) +// sstore(10, d) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul index 65a325d6c..696d0b111 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul @@ -5,5 +5,6 @@ // step: expressionSimplifier // // { -// mstore(0, and(calldataload(0), 255)) +// let _4 := 0 +// mstore(_4, and(calldataload(_4), 255)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul index d4e35af33..81fe7e117 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul @@ -5,5 +5,6 @@ // step: expressionSimplifier // // { -// mstore(0, and(calldataload(0), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) +// let _4 := 0 +// mstore(_4, and(calldataload(_4), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul index b7bc3e4f9..ccb490892 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul @@ -1,6 +1,7 @@ { function f(a) -> b { } let c := sub(f(0), f(1)) + sstore(0, c) } // ---- // step: expressionSimplifier @@ -8,5 +9,7 @@ // { // function f(a) -> b // { } -// let c := sub(f(0), f(1)) +// let _2 := f(1) +// let _3 := 0 +// sstore(_3, sub(f(_3), _2)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul index b43440128..7f44c2208 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul @@ -2,6 +2,7 @@ function f1() -> a { } function f2() -> b { } let c := sub(f1(), f2()) + sstore(0, c) } // ---- // step: expressionSimplifier @@ -11,5 +12,5 @@ // { } // function f2() -> b // { } -// let c := sub(f1(), f2()) +// sstore(0, sub(f1(), f2())) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul index c0fa43e2c..6ed704aea 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul @@ -1,13 +1,14 @@ // Even if the functions pass the equality check, they are not movable. { - function f() -> a { } + function f() -> a { mstore(0, 1) } let b := sub(f(), f()) + sstore(b, 8) } // ---- // step: expressionSimplifier // // { // function f() -> a -// { } -// let b := sub(f(), f()) +// { mstore(a, 1) } +// sstore(sub(f(), f()), 8) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul index d153ae724..37065cd4d 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul @@ -1,11 +1,17 @@ // The first argument of div is not constant. // keccak256 is not movable. { + sstore(0, msize()) let a := div(keccak256(0, 0), 0) + sstore(20, a) } // ---- // step: expressionSimplifier // // { -// let a := div(keccak256(0, 0), 0) +// let _1 := msize() +// let _2 := 0 +// sstore(_2, _1) +// pop(keccak256(_2, _2)) +// sstore(20, 0) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul index e30a0418c..af34e76bd 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_call.yul @@ -1,5 +1,5 @@ { - pop(byte(0, shr(0x8, call(0, 0, 0, 0, 0, 0, 0)))) + sstore(0, byte(0, shr(0x8, call(0, 0, 0, 0, 0, 0, 0)))) } // ==== // EVMVersion: >=constantinople @@ -7,5 +7,7 @@ // step: expressionSimplifier // // { -// pop(byte(0, shr(0x8, call(0, 0, 0, 0, 0, 0, 0)))) +// let _1 := 0 +// pop(call(_1, _1, _1, _1, _1, _1, _1)) +// sstore(_1, 0) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul index f24add1dd..0d9513ec2 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func.yul @@ -1,6 +1,6 @@ { function f() -> x { mstore(0, 1337) } - pop(byte(0, shr(0x8, f()))) + mstore(0, byte(0, shr(0x8, f()))) } // ==== // EVMVersion: >=constantinople @@ -9,6 +9,7 @@ // // { // function f() -> x -// { mstore(0, 1337) } -// pop(byte(0, shr(0x8, f()))) +// { mstore(x, 1337) } +// pop(f()) +// mstore(0, 0) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul index 3fc5ee558..448e071d8 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/pop_byte_shr_func_trivial.yul @@ -1,14 +1,10 @@ { function f() -> x {} - pop(byte(0, shr(0x8, f()))) + sstore(0, byte(0, shr(0x8, f()))) } // ==== // EVMVersion: >=constantinople // ---- // step: expressionSimplifier // -// { -// function f() -> x -// { } -// pop(byte(0, shr(0x8, f()))) -// } +// { sstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul index fbc5befd0..d87b84f59 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul @@ -7,7 +7,8 @@ // step: expressionSimplifier // // { -// let x := mload(0) -// x := 0 -// mstore(0, 7) +// let _1 := 0 +// let x := mload(_1) +// x := _1 +// mstore(_1, 7) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul index b81ae9619..060a4e13f 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul @@ -3,6 +3,8 @@ let b := and(shr(248, calldataload(0)), 0xff) let c := and(shr(249, calldataload(0)), 0xfa) let d := and(shr(247, calldataload(0)), 0xff) + sstore(a, b) + sstore(c, d) } // ==== // EVMVersion: >=constantinople @@ -10,8 +12,12 @@ // step: expressionSimplifier // // { -// let a := shr(248, calldataload(0)) -// let b := shr(248, calldataload(0)) -// let c := and(shr(249, calldataload(0)), 0xfa) -// let d := and(shr(247, calldataload(0)), 0xff) +// let _2 := calldataload(0) +// let _5 := 0xff +// let a := shr(248, _2) +// let b := shr(248, _2) +// let c := and(shr(249, _2), 0xfa) +// let d := and(shr(247, _2), _5) +// sstore(a, b) +// sstore(c, d) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul index 550c7becb..88263e98e 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul @@ -3,6 +3,8 @@ let b := shr(299, calldataload(1)) let c := shl(255, calldataload(2)) let d := shr(255, calldataload(3)) + sstore(a, b) + sstore(c, d) } // ==== // EVMVersion: >=constantinople @@ -12,6 +14,10 @@ // { // let a := 0 // let b := 0 -// let c := shl(255, calldataload(2)) -// let d := shr(255, calldataload(3)) +// let _8 := calldataload(2) +// let _9 := 255 +// let c := shl(_9, _8) +// let d := shr(_9, calldataload(3)) +// sstore(a, b) +// sstore(c, d) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul index c1c0093ef..9b0087dd7 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul @@ -2,12 +2,15 @@ { function f() -> c, d { let y := add(d, add(c, 7)) + sstore(0, y) } + let t, v := f() } // ---- // step: expressionSimplifier // // { // function f() -> c, d -// { let y := 7 } +// { sstore(d, 7) } +// let t, v := f() // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul index 9ca956c10..32c877572 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul @@ -1,7 +1,11 @@ { let a := add(0, mload(0)) + sstore(0, a) } // ---- // step: expressionSimplifier // -// { let a := mload(0) } +// { +// let _1 := 0 +// sstore(_1, mload(_1)) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul index 693c05c42..8a9bb7c19 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul @@ -1,9 +1,9 @@ { - let ret := balance(address()) + sstore(0, balance(address())) } // ==== // EVMVersion: =istanbul @@ -9,5 +10,5 @@ // // { // let a := address() -// let ret := selfbalance() +// sstore(a, selfbalance()) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul index 7b0a7524e..bc3c6c4d7 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul @@ -1,9 +1,9 @@ { - let ret := balance(address()) + sstore(0, balance(address())) } // ==== // EVMVersion: >=istanbul // ---- // step: expressionSimplifier // -// { let ret := selfbalance() } +// { sstore(0, selfbalance()) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul index e88877365..b052fe403 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul @@ -2,11 +2,12 @@ { let c, d let y := add(d, add(c, 7)) + sstore(0, y) } // ---- // step: expressionSimplifier // // { // let c, d -// let y := 7 +// sstore(d, 7) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul index d66d4efb2..9dd4e3365 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul @@ -3,12 +3,9 @@ let c let d let y := add(d, add(c, 7)) + sstore(8, y) } // ---- // step: expressionSimplifier // -// { -// let c -// let d -// let y := 7 -// } +// { sstore(8, 7) } diff --git a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul new file mode 100644 index 000000000..82ab48a51 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/connected.yul @@ -0,0 +1,62 @@ +{ + mstore(0x40, memoryguard(0)) + function g() -> a, b { + a := 21 + let $c := 1 + b,a,$c := z() + } + function f() -> x { + let $x2 + $x2 := 42 + let $x3, $x4 := g() + x := mul(add($x2, $x3), h($x4)) + sstore($x3, $x4) + } + function h(v) -> a { + let x, $z, y := z() + a, $z, v := z() + } + function z() -> a,b,c { let $x := 0 } + sstore(0, f()) + let x, y := g() +} +// ---- +// step: fakeStackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// function g() -> a, b +// { +// a := 21 +// mstore(0x60, 1) +// let b_1, a_2, $c_3 := z() +// mstore(0x60, $c_3) +// a := a_2 +// b := b_1 +// } +// function f() -> x +// { +// mstore(0x20, 0) +// mstore(0x20, 42) +// let $x3_4, $x4_5 := g() +// mstore(0x00, $x4_5) +// mstore(0x40, $x3_4) +// x := mul(add(mload(0x20), mload(0x40)), h(mload(0x00))) +// sstore(mload(0x40), mload(0x00)) +// } +// function h(v) -> a_1 +// { +// let x_2_6, $z_7, y_8 := z() +// mstore(0x60, $z_7) +// let y := y_8 +// let x_2 := x_2_6 +// let a_1_9, $z_10, v_11 := z() +// mstore(0x60, $z_10) +// v := v_11 +// a_1 := a_1_9 +// } +// function z() -> a_3, b_4, c +// { mstore(0x80, 0) } +// sstore(0, f()) +// let x_5, y_6 := g() +// } diff --git a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/function_arg.yul b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/function_arg.yul new file mode 100644 index 000000000..6ce2e34b4 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/function_arg.yul @@ -0,0 +1,20 @@ +{ + mstore(0x40, memoryguard(0)) + let $x := 0 + sstore(0, $x) + function h($hx) -> y { + y := $hx + } + sstore(1, h(32)) +} +// ---- +// step: fakeStackLimitEvader +// +// { +// mstore(0x40, memoryguard(0x40)) +// mstore(0x00, 0) +// sstore(0, mload(0x00)) +// function h($hx) -> y +// { y := $hx } +// sstore(1, h(32)) +// } diff --git a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/outer_block.yul b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/outer_block.yul new file mode 100644 index 000000000..023100cdd --- /dev/null +++ b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/outer_block.yul @@ -0,0 +1,13 @@ +{ + mstore(0x40, memoryguard(0x80)) + let $x := 42 + sstore(42, $x) +} +// ---- +// step: fakeStackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// mstore(0x80, 42) +// sstore(42, mload(0x80)) +// } diff --git a/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul new file mode 100644 index 000000000..d2fcb116e --- /dev/null +++ b/test/libyul/yulOptimizerTests/fakeStackLimitEvader/stub.yul @@ -0,0 +1,88 @@ +{ + mstore(0x40, memoryguard(0)) + function f() { + let $fx + let $fy := 42 + sstore($fx, $fy) + $fx := 21 + } + function g(gx) { + let $gx, $gy := tuple2() + { $gx, $gy := tuple2() } + { $gx, gx := tuple2() } + { gx, $gy := tuple2() } + } + function h(hx, hy, hz, hw) { + let $hx, $hy, $hz, $hw := tuple4() + { hx, $hy, hz, $hw := tuple4() } + { $hx, $hy, hz, hw := tuple4() } + } + function tuple2() -> a, b {} + function tuple4() -> a, b, c, d {} + f() + g(0) + h(1, 2, 3, 4) +} +// ---- +// step: fakeStackLimitEvader +// +// { +// mstore(0x40, memoryguard(0x80)) +// function f() +// { +// mstore(0x40, 0) +// mstore(0x60, 42) +// sstore(mload(0x40), mload(0x60)) +// mstore(0x40, 21) +// } +// function g(gx) +// { +// let $gx_1, $gy_2 := tuple2() +// mstore(0x40, $gy_2) +// mstore(0x60, $gx_1) +// { +// let $gx_3, $gy_4 := tuple2() +// mstore(0x40, $gy_4) +// mstore(0x60, $gx_3) +// } +// { +// let $gx_5, gx_6 := tuple2() +// mstore(0x60, $gx_5) +// gx := gx_6 +// } +// { +// let gx_7, $gy_8 := tuple2() +// mstore(0x40, $gy_8) +// gx := gx_7 +// } +// } +// function h(hx, hy, hz, hw) +// { +// let $hx_9, $hy_10, $hz_11, $hw_12 := tuple4() +// mstore(0x00, $hw_12) +// mstore(0x60, $hz_11) +// mstore(0x40, $hy_10) +// mstore(0x20, $hx_9) +// { +// let hx_13, $hy_14, hz_15, $hw_16 := tuple4() +// mstore(0x00, $hw_16) +// mstore(0x40, $hy_14) +// hz := hz_15 +// hx := hx_13 +// } +// { +// let $hx_17, $hy_18, hz_19, hw_20 := tuple4() +// mstore(0x40, $hy_18) +// mstore(0x20, $hx_17) +// hw := hw_20 +// hz := hz_19 +// } +// } +// function tuple2() -> a, b +// { } +// function tuple4() -> a_1, b_2, c, d +// { } +// f() +// g(0) +// h(1, 2, 3, 4) +// } diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul index 56cac2704..a5194457a 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul @@ -9,22 +9,25 @@ // { // { // let _1 := 7 -// let a_6 := 3 -// let x_7 := 0 -// x_7 := add(a_6, a_6) -// let b_8 := x_7 -// let c_9 := _1 -// let y_10 := 0 -// y_10 := mul(mload(c_9), f(b_8)) -// let y_1 := y_10 +// let a_8 := 3 +// let x_9 := 0 +// x_9 := add(a_8, a_8) +// let b_10 := x_9 +// let c_11 := _1 +// let y_12 := 0 +// let a_6_13 := b_10 +// let x_7_14 := 0 +// x_7_14 := add(a_6_13, a_6_13) +// y_12 := mul(mload(c_11), x_7_14) +// let y_1 := y_12 // } // function f(a) -> x // { x := add(a, a) } // function g(b, c) -> y // { -// let a_13 := b -// let x_14 := 0 -// x_14 := add(a_13, a_13) -// y := mul(mload(c), x_14) +// let a_6 := b +// let x_7 := 0 +// x_7 := add(a_6, a_6) +// y := mul(mload(c), x_7) // } // } diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul index df3119103..14e977dd3 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul @@ -26,20 +26,14 @@ // step: fullInliner // // { -// { -// let x_8 := 100 -// mstore(0, x_8) -// mstore(7, h()) -// g(10) -// mstore(1, x_8) -// } +// { f(100) } // function f(x) // { // mstore(0, x) -// let t_14 := 0 -// t_14 := 2 -// mstore(7, t_14) -// let x_1_15 := 10 +// let t_8 := 0 +// t_8 := 2 +// mstore(7, t_8) +// let x_1_9 := 10 // f(1) // mstore(1, x) // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul index 2f400186a..248fcc661 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul @@ -1081,13 +1081,13 @@ // let _2 := mload(0) // if slt(sub(_1, _2), 64) { revert(0, 0) } // sstore(0, and(calldataload(_2), sub(shl(160, 1), 1))) -// let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8)) +// let x0, x1, x2, x3, x4 := abi_decode_addresst_uint256t_bytes_calldatat_enum$_Operation(mload(7), mload(8)) // sstore(x1, x0) // sstore(x3, x2) // sstore(1, x4) -// pop(abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(mload(30), mload(31), mload(32), mload(33), mload(34), mload(35), mload(36), mload(37), mload(38), mload(39), mload(40), mload(41))) +// pop(abi_encode_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint(mload(30), mload(31), mload(32), mload(33), mload(34), mload(35), mload(36), mload(37), mload(38), mload(39), mload(40), mload(41))) // } -// function abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(headStart, dataEnd) -> value0, value1, value2, value3, value4 +// function abi_decode_addresst_uint256t_bytes_calldatat_enum$_Operation(headStart, dataEnd) -> value0, value1, value2, value3, value4 // { // if slt(sub(dataEnd, headStart), 128) { revert(value4, value4) } // value0 := and(calldataload(headStart), sub(shl(160, 1), 1)) @@ -1106,7 +1106,7 @@ // if iszero(lt(_3, 3)) { revert(value4, value4) } // value4 := _3 // } -// function abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(headStart, value10, value9, value8, value7, value6, value5, value4, value3, value2, value1, value0) -> tail +// function abi_encode_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint(headStart, value10, value9, value8, value7, value6, value5, value4, value3, value2, value1, value0) -> tail // { // tail := add(headStart, 352) // mstore(headStart, value0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul index 5e6e0305d..44183b555 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul @@ -473,25 +473,25 @@ // let i := _1 // for { } lt(i, length) { i := add(i, 1) } // { -// abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(mload(srcPtr), pos) +// let _3 := mload(srcPtr) +// let pos_1 := pos +// let srcPtr_1 := _3 +// let i_1 := _1 +// for { } lt(i_1, 0x3) { i_1 := add(i_1, 1) } +// { +// mstore(pos_1, and(mload(srcPtr_1), sub(shl(160, 1), 1))) +// srcPtr_1 := add(srcPtr_1, 0x20) +// pos_1 := add(pos_1, 0x20) +// } // srcPtr := add(srcPtr, 0x20) // pos := add(pos, 0x60) // } -// let _3 := mload(64) -// let _4 := mload(0x20) -// if slt(sub(_3, _4), 128) { revert(_1, _1) } -// let offset := calldataload(add(_4, 64)) -// let _5 := 0xffffffffffffffff -// if gt(offset, _5) { revert(_1, _1) } -// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_4, offset), _3) -// let offset_1 := calldataload(add(_4, 0x60)) -// if gt(offset_1, _5) { revert(_1, _1) } -// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_4, offset_1), _3) -// sstore(calldataload(_4), calldataload(add(_4, 0x20))) -// sstore(value2, value3) +// let a, b, c, d := abi_decode_uint256t_uint256t_array$_t_uint256_$dynt_array$_t_array$_t_uint256_memory_$dyn(mload(0x20), mload(64)) +// sstore(a, b) +// sstore(c, d) // sstore(_1, pos) // } -// function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset, end) -> array +// function abi_decode_t_array$_t_array$_t_uint256_memory_$dyn(offset, end) -> array // { // let _1 := 0x1f // if iszero(slt(add(offset, _1), end)) { revert(array, array) } @@ -508,14 +508,13 @@ // for { } lt(i, length) { i := add(i, 1) } // { // if iszero(slt(add(src, _1), end)) { revert(0, 0) } -// let _4 := 0x2 -// let dst_1 := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(_4)) +// let dst_1 := allocateMemory(_3) // let dst_2 := dst_1 // let src_1 := src -// let _5 := add(src, _3) -// if gt(_5, end) { revert(0, 0) } +// let _4 := add(src, _3) +// if gt(_4, end) { revert(0, 0) } // let i_1 := 0 -// for { } lt(i_1, _4) { i_1 := add(i_1, 1) } +// for { } lt(i_1, 0x2) { i_1 := add(i_1, 1) } // { // mstore(dst_1, calldataload(src_1)) // dst_1 := add(dst_1, _2) @@ -523,39 +522,38 @@ // } // mstore(dst, dst_2) // dst := add(dst, _2) -// src := _5 +// src := _4 // } // } -// function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset, end) -> array +// function abi_decode_uint256t_uint256t_array$_t_uint256_$dynt_array$_t_array$_t_uint256_memory_$dyn(headStart, dataEnd) -> value0, value1, value2, value3 // { -// if iszero(slt(add(offset, 0x1f), end)) { revert(array, array) } -// let length := calldataload(offset) -// array := allocateMemory(array_allocation_size_t_array$_t_address_$dyn_memory(length)) -// let dst := array -// mstore(array, length) -// let _1 := 0x20 -// dst := add(array, _1) -// let src := add(offset, _1) -// if gt(add(add(offset, mul(length, _1)), _1), end) { revert(0, 0) } -// let i := 0 +// if slt(sub(dataEnd, headStart), 128) { revert(value2, value2) } +// value0 := calldataload(headStart) +// let _1 := 32 +// value1 := calldataload(add(headStart, _1)) +// let offset := calldataload(add(headStart, 64)) +// let _2 := 0xffffffffffffffff +// if gt(offset, _2) { revert(value2, value2) } +// let _3 := add(headStart, offset) +// if iszero(slt(add(_3, 0x1f), dataEnd)) { revert(value2, value2) } +// let length := calldataload(_3) +// let dst := allocateMemory(array_allocation_size_t_array$_t_address_$dyn_memory(length)) +// let dst_1 := dst +// mstore(dst, length) +// dst := add(dst, _1) +// let src := add(_3, _1) +// if gt(add(add(_3, mul(length, _1)), _1), dataEnd) { revert(value2, value2) } +// let i := value2 // for { } lt(i, length) { i := add(i, 1) } // { // mstore(dst, calldataload(src)) // dst := add(dst, _1) // src := add(src, _1) // } -// } -// function abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(value, pos) -// { -// let srcPtr := value -// let i := 0 -// for { } lt(i, 0x3) { i := add(i, 1) } -// { -// mstore(pos, and(mload(srcPtr), sub(shl(160, 1), 1))) -// let _1 := 0x20 -// srcPtr := add(srcPtr, _1) -// pos := add(pos, _1) -// } +// value2 := dst_1 +// let offset_1 := calldataload(add(headStart, 96)) +// if gt(offset_1, _2) { revert(value3, value3) } +// value3 := abi_decode_t_array$_t_array$_t_uint256_memory_$dyn(add(headStart, offset_1), dataEnd) // } // function allocateMemory(size) -> memPtr // { @@ -569,9 +567,4 @@ // if gt(length, 0xffffffffffffffff) { revert(size, size) } // size := add(mul(length, 0x20), 0x20) // } -// function array_allocation_size_t_array$_t_uint256_$2_memory(length) -> size -// { -// if gt(length, 0xffffffffffffffff) { revert(size, size) } -// size := mul(length, 0x20) -// } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and.yul b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and.yul new file mode 100644 index 000000000..1abea23e7 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and.yul @@ -0,0 +1,17 @@ +{ + let x := calldataload(0) + let a := and(0xff, shr(248, shl(248, shr(248, x)))) + let b := shr(12, shl(8, and(x, 0xf0f0))) + sstore(a, b) +} +// ==== +// EVMVersion: >byzantium +// ---- +// step: fullSuite +// +// { +// { +// let x := calldataload(0) +// sstore(shr(248, x), and(shr(4, x), 3855)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_2.yul b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_2.yul new file mode 100644 index 000000000..513a23aa5 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_2.yul @@ -0,0 +1,35 @@ +{ + let x := calldataload(0) + let a := and(0xff, shr(248, shl(248, shr(248, and(x, 0xf))))) + let b := shl(12, shr(4, and(x, 0xf0f0))) + let c := shl(12, shr(4, and(0xf0f0, x))) + let d := shl(12, shr(255, and(0xf0f0, x))) + let e := shl(255, shr(4, and(0xf0f0, x))) + let f := shl(12, shr(256, and(0xf0f0, x))) + let g := shl(256, shr(4, and(0xf0f0, x))) + sstore(10, a) + sstore(11, b) + sstore(12, c) + sstore(13, d) + sstore(14, e) + sstore(15, f) + sstore(16, g) +} +// ==== +// EVMVersion: >byzantium +// ---- +// step: fullSuite +// +// { +// { +// let x := calldataload(0) +// let b := and(shl(8, x), 15790080) +// sstore(10, 0) +// sstore(11, b) +// sstore(12, b) +// sstore(13, 0) +// sstore(14, and(shl(251, x), shl(255, 1))) +// sstore(0xf, 0) +// sstore(16, 0) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_3.yul b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_3.yul new file mode 100644 index 000000000..17de07de7 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_3.yul @@ -0,0 +1,32 @@ +{ + let x := calldataload(0) + let a := shl(12, shr(4, x)) + let b := shl(4, shr(12, x)) + let c := shr(12, shl(4, x)) + let d := shr(4, shl(12, x)) + let e := shl(150, shr(2, shl(150, x))) + sstore(15, x) + sstore(16, a) + sstore(17, b) + sstore(18, c) + sstore(19, d) + sstore(20, e) +} +// ==== +// EVMVersion: >byzantium +// ---- +// step: fullSuite +// +// { +// { +// let x := calldataload(0) +// let _1 := shl(8, x) +// let _2 := shr(8, x) +// sstore(15, x) +// sstore(16, and(_1, not(4095))) +// sstore(17, and(_2, sub(shl(248, 1), 16))) +// sstore(18, and(_2, sub(shl(244, 1), 1))) +// sstore(19, and(_1, sub(shl(252, 1), 256))) +// sstore(20, 0) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_unsplit.yul b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_unsplit.yul new file mode 100644 index 000000000..923a18f4f --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/combine_shift_and_and_unsplit.yul @@ -0,0 +1,19 @@ +{ + let x := calldataload(0) + // This checks that the expression simplifier + // does not modify unsplit expressions. + let a := and(0xff, shr(248, shl(248, shr(248, x)))) + let b := shr(12, shl(8, and(x, 0xf0f0))) + sstore(a, b) +} +// ==== +// EVMVersion: >byzantium +// ---- +// step: fullSuite +// +// { +// { +// let x := calldataload(0) +// sstore(shr(248, x), and(shr(4, x), 3855)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/create2_and_mask.yul b/test/libyul/yulOptimizerTests/fullSuite/create2_and_mask.yul new file mode 100644 index 000000000..813c2706e --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/create2_and_mask.yul @@ -0,0 +1,21 @@ +{ + // This does not optimize the masks away. Due to the way the expression simplifier + // is built, it would have to create another `create2` opcode for the simplification + // which would be fatal. + let a := and(create2(0, 0, 0x20, 0), 0xffffffffffffffffffffffffffffffffffffffff) + let b := and(0xffffffffffffffffffffffffffffffffffffffff, create2(0, 0, 0x20, 0)) + sstore(a, b) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: fullSuite +// +// { +// { +// let _1 := sub(shl(160, 1), 1) +// let _2 := 0 +// let a := and(create2(_2, _2, 0x20, _2), _1) +// sstore(a, and(_1, create2(_2, _2, 0x20, _2))) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/create_and_mask.yul b/test/libyul/yulOptimizerTests/fullSuite/create_and_mask.yul new file mode 100644 index 000000000..c89c620bb --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/create_and_mask.yul @@ -0,0 +1,20 @@ +{ + // This does not optimize the masks away. Due to the way the expression simplifier + // is built, it would have to create another `create` opcode for the simplification + // which would be fatal. + let a := and(create(0, 0, 0x20), 0xffffffffffffffffffffffffffffffffffffffff) + let b := and(0xffffffffffffffffffffffffffffffffffffffff, create(0, 0, 0x20)) + sstore(a, b) +} +// ==== +// EVMVersion: >=istanbul +// ---- +// step: fullSuite +// +// { +// { +// let _1 := sub(shl(160, 1), 1) +// let a := and(create(0, 0, 0x20), _1) +// sstore(a, and(_1, create(0, 0, 0x20))) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/name_cleaner_reserved.yul b/test/libyul/yulOptimizerTests/fullSuite/name_cleaner_reserved.yul new file mode 100644 index 000000000..576f5abb9 --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/name_cleaner_reserved.yul @@ -0,0 +1,34 @@ +{ + // This function name can be shortened, the other cannot. + function nonmstore_(x) { + nonmstore_(x) + sstore(10, calldataload(2)) + } + function mstore_(x) -> y { + let t3_3_ := mstore_(x) + y := 8 + sstore(y, calldataload(y)) + } + let t2_ := mstore_(7) + nonmstore_(70) +} +// ---- +// step: fullSuite +// +// { +// { +// pop(mstore_(7)) +// nonmstore(70) +// } +// function nonmstore(x) +// { +// nonmstore(x) +// sstore(10, calldataload(2)) +// } +// function mstore_(x) -> y +// { +// pop(mstore_(x)) +// y := 8 +// sstore(y, calldataload(y)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul index 78af81f38..102a47bc2 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul @@ -36,16 +36,16 @@ // // { // { -// let a, b := abi_decode_t_bytes_calldata_ptr(mload(0), mload(1)) -// let a_1, b_1 := abi_decode_t_bytes_calldata_ptr(a, b) -// let a_2, b_2 := abi_decode_t_bytes_calldata_ptr(a_1, b_1) -// let a_3, b_3 := abi_decode_t_bytes_calldata_ptr(a_2, b_2) -// let a_4, b_4 := abi_decode_t_bytes_calldata_ptr(a_3, b_3) -// let a_5, b_5 := abi_decode_t_bytes_calldata_ptr(a_4, b_4) -// let a_6, b_6 := abi_decode_t_bytes_calldata_ptr(a_5, b_5) +// let a, b := abi_decode_t_bytes_calldata(mload(0), mload(1)) +// let a_1, b_1 := abi_decode_t_bytes_calldata(a, b) +// let a_2, b_2 := abi_decode_t_bytes_calldata(a_1, b_1) +// let a_3, b_3 := abi_decode_t_bytes_calldata(a_2, b_2) +// let a_4, b_4 := abi_decode_t_bytes_calldata(a_3, b_3) +// let a_5, b_5 := abi_decode_t_bytes_calldata(a_4, b_4) +// let a_6, b_6 := abi_decode_t_bytes_calldata(a_5, b_5) // mstore(a_6, b_6) // } -// function abi_decode_t_bytes_calldata_ptr(offset, end) -> arrayPos, length +// function abi_decode_t_bytes_calldata(offset, end) -> arrayPos, length // { // if iszero(slt(add(offset, 0x1f), end)) { revert(arrayPos, arrayPos) } // length := calldataload(offset) diff --git a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul index 56a2d6cfe..b417991c2 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul @@ -49,7 +49,7 @@ // sstore(not(gcd(10, 15)), 1) // sstore(0, 0) // sstore(2, 1) -// pop(foo_singlereturn_1(calldataload(0), calldataload(3))) +// extcodecopy(1, msize(), 1, 1) // sstore(0, 0) // sstore(3, 1) // } @@ -59,6 +59,4 @@ // case 0 { out := _a } // default { out := gcd(_b, mod(_a, _b)) } // } -// function foo_singlereturn_1(in, in_1) -> out -// { extcodecopy(1, msize(), 1, 1) } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul new file mode 100644 index 000000000..b7f0b4afb --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner.yul @@ -0,0 +1,34 @@ +{ + let x, y := foo(sload(0),sload(32)) + sstore(0, x) + sstore(0, y) + x, y := foo(sload(32), sload(8)) + + function foo(a, b) -> out1, out2 + { + out1 := mload(32) + out1 := sload(out1) + out2 := add(out1, 1) + extcodecopy(out1, out2, 1, b) + // to prevent foo from getting inlined + if iszero(out1) { leave } + } +} +// ---- +// step: fullSuite +// +// { +// { +// let out1, out2 := foo(sload(32)) +// sstore(0, out1) +// sstore(0, out2) +// let out1_1, out2_1 := foo(sload(8)) +// } +// function foo(b) -> out1, out2 +// { +// out1 := sload(mload(32)) +// out2 := add(out1, 1) +// extcodecopy(out1, out2, 1, b) +// if iszero(out1) { leave } +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul new file mode 100644 index 000000000..b531842db --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul @@ -0,0 +1,39 @@ +{ + sstore(f(1), 1) + sstore(f(2), 1) + sstore(f(3), 1) + function f(a) -> x { + for {let b := 10} iszero(b) { b := sub(b, 1) } + { + a := calldataload(0) + mstore(a, x) + // to prevent f from getting inlined + if iszero(a) { leave } + } + } +} +// ---- +// step: fullSuite +// +// { +// { +// f() +// sstore(0, 1) +// f() +// sstore(0, 1) +// f() +// sstore(0, 1) +// } +// function f() +// { +// let b := 10 +// let _1 := 0 +// let a := calldataload(_1) +// let _2 := iszero(a) +// for { } iszero(b) { b := add(b, not(0)) } +// { +// mstore(a, _1) +// if _2 { leave } +// } +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul new file mode 100644 index 000000000..69b4517eb --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_recursion.yul @@ -0,0 +1,29 @@ +{ + let j, k, l := f(1, 2, 3) + sstore(0, j) + sstore(1, k) + sstore(1, l) + function f(a, b, c) -> x, y, z + { + x, y, z := f(1, 2, 3) + x := add(x, 1) + } +} +// ---- +// step: fullSuite +// +// { +// { +// let x, y, z := f() +// sstore(0, x) +// sstore(1, y) +// sstore(1, z) +// } +// function f() -> x, y, z +// { +// let x_1, y_1, z_1 := f() +// y := y_1 +// z := z_1 +// x := add(x_1, 1) +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul new file mode 100644 index 000000000..14f0137cb --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_return.yul @@ -0,0 +1,37 @@ +{ + let x, y, z := foo(sload(0),sload(32)) + sstore(0, x) + sstore(0, y) + sstore(0, z) + x, y, z := foo(sload(32), sload(8)) + + // out3 is unassigned. + function foo(a, b) -> out1, out2, out3 + { + out1 := mload(32) + out1 := sload(out1) + out2 := add(out1, 1) + extcodecopy(out1, out1, 1, b) + // to prevent foo from getting inlined + if iszero(out1) { leave } + } +} +// ---- +// step: fullSuite +// +// { +// { +// let out1, out2 := foo(sload(32)) +// sstore(0, out1) +// sstore(0, out2) +// sstore(0, 0) +// let out1_1, out2_1 := foo(sload(8)) +// } +// function foo(b) -> out1, out2 +// { +// out1 := sload(mload(32)) +// out2 := add(out1, 1) +// extcodecopy(out1, out1, 1, b) +// if iszero(out1) { leave } +// } +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul new file mode 100644 index 000000000..531b1a6ce --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul @@ -0,0 +1,31 @@ +{ + sstore(f(1), 1) + sstore(f(2), 1) + sstore(f(3), 1) + function f(a) -> x { + // The usage of a is redundant + a := calldataload(0) + mstore(a, x) + // to prevent f from getting inlined + if iszero(a) { leave } + } +} +// ---- +// step: fullSuite +// +// { +// { +// f() +// sstore(0, 1) +// f() +// sstore(0, 1) +// f() +// sstore(0, 1) +// } +// function f() +// { +// let a := calldataload(0) +// mstore(a, 0) +// if iszero(a) { leave } +// } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/addmod.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/addmod.yul new file mode 100644 index 000000000..88c60a0ee --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/addmod.yul @@ -0,0 +1,31 @@ +{ + let x := calldataload(0) + let y := calldataload(32) + let z := calldataload(64) + let result := addmod(x, y, z) + + // should be zero + if gt(result, z) { sstore(0, 1) } + + // addmod is equal to mod of sum for small numbers + if and(and(lt(x, 1000), lt(y, 1000)), lt(z, 1000)) { + if eq(result, mod(add(x, y), z)) { sstore(0, 9) } + } + + // but not in general + if and(and(gt(x, sub(0, 5)), gt(y, sub(0, 2))), eq(z, 3)) { + if eq(result, mod(add(x, y), z)) { sstore(0, 5) } + } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := calldataload(0) +// let y := calldataload(32) +// let z := calldataload(64) +// let result := addmod(x, y, z) +// if 0 { } +// if and(and(lt(x, 1000), lt(y, 1000)), lt(z, 1000)) { if 1 { sstore(0, 9) } } +// if and(and(gt(x, sub(0, 5)), gt(y, sub(0, 2))), eq(z, 3)) { if 0 { } } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith.yul new file mode 100644 index 000000000..7ff930766 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith.yul @@ -0,0 +1,13 @@ +{ + let x := 7 + let y := 8 + if eq(add(x, y), 15) { } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := 7 +// let y := 8 +// if 1 { } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith_movable.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith_movable.yul new file mode 100644 index 000000000..2080a678c --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith_movable.yul @@ -0,0 +1,19 @@ +{ + function f() -> z + { + z := 15 + } + let x := 7 + let y := 8 + if eq(add(x, y), f()) { } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// function f() -> z +// { z := 15 } +// let x := 7 +// let y := 8 +// if eq(add(x, y), f()) { } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith_non_movable.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith_non_movable.yul new file mode 100644 index 000000000..ed50224d0 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/arith_non_movable.yul @@ -0,0 +1,23 @@ +{ + function f() -> z + { + sstore(1, 15) + z := 15 + } + let x := 7 + let y := 8 + if eq(add(x, y), f()) { } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// function f() -> z +// { +// sstore(1, 15) +// z := 15 +// } +// let x := 7 +// let y := 8 +// if eq(add(x, y), f()) { } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/mulcheck.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/mulcheck.yul new file mode 100644 index 000000000..31a342339 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/mulcheck.yul @@ -0,0 +1,32 @@ +{ + let vloc_x := calldataload(0) + let vloc_y := calldataload(1) + if lt(vloc_x, shl(100, 1)) { + if lt(vloc_y, shl(100, 1)) { + if iszero(and(iszero(iszero(vloc_x)), gt(vloc_y, div(not(0), vloc_x)))) { + let vloc := mul(vloc_x, vloc_y) + sstore(0, vloc) + } + } + } +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: reasoningBasedSimplifier +// +// { +// let vloc_x := calldataload(0) +// let vloc_y := calldataload(1) +// if lt(vloc_x, shl(100, 1)) +// { +// if lt(vloc_y, shl(100, 1)) +// { +// if 1 +// { +// let vloc := mul(vloc_x, vloc_y) +// sstore(0, vloc) +// } +// } +// } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/mulmod.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/mulmod.yul new file mode 100644 index 000000000..f5226acf7 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/mulmod.yul @@ -0,0 +1,31 @@ +{ + let x := calldataload(0) + let y := calldataload(32) + let z := calldataload(64) + let result := mulmod(x, y, z) + + // should be zero + if gt(result, z) { sstore(0, 1) } + + // mulmod is equal to mod of product for small numbers + if and(and(lt(x, 1000), lt(y, 1000)), lt(z, 1000)) { + if eq(result, mod(mul(x, y), z)) { sstore(0, 9) } + } + + // but not in general + if and(and(gt(x, sub(0, 5)), eq(y, 2)), eq(z, 3)) { + if eq(result, mod(mul(x, y), z)) { sstore(0, 5) } + } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := calldataload(0) +// let y := calldataload(32) +// let z := calldataload(64) +// let result := mulmod(x, y, z) +// if 0 { } +// if and(and(lt(x, 1000), lt(y, 1000)), lt(z, 1000)) { if 1 { sstore(0, 9) } } +// if and(and(gt(x, sub(0, 5)), eq(y, 2)), eq(z, 3)) { if 0 { } } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/negative_rounding.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/negative_rounding.yul new file mode 100644 index 000000000..6e4b3f5ed --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/negative_rounding.yul @@ -0,0 +1,16 @@ +{ + let x := sub(0, 7) + let y := 2 + // (-7)/2 == -3 on the evm + if iszero(add(sdiv(x, y), 3)) { } + if iszero(add(sdiv(x, y), 4)) { } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := sub(0, 7) +// let y := 2 +// if 1 { } +// if 0 { } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/nested.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/nested.yul new file mode 100644 index 000000000..d7002c99b --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/nested.yul @@ -0,0 +1,26 @@ +{ + let x := calldataload(2) + let t := lt(x, 20) + if t { + if lt(x, 21) { } + if lt(x, 20) { } + if lt(x, 19) { } + if gt(x, 20) { } + if iszero(gt(x, 20)) { } + } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := calldataload(2) +// let t := lt(x, 20) +// if t +// { +// if 1 { } +// if 1 { } +// if lt(x, 19) { } +// if 0 { } +// if 1 { } +// } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/signed_division.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/signed_division.yul new file mode 100644 index 000000000..1e409079e --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/signed_division.yul @@ -0,0 +1,31 @@ +{ + let y := calldataload(0) + let t := calldataload(32) + + if sgt(sub(y, 1), y) { + // y - 1 > y, i.e. y is the most negative value + if eq(sdiv(y, sub(0, 1)), y) { + // should be true: y / -1 == y + sstore(0, 7) + } + if iszero(eq(y, t)) { + // t is not the most negative value + if eq(sdiv(t, sub(0, 1)), sub(0, t)) { + // should be true: t / -1 = 0 - t + sstore(1, 7) + } + } + } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let y := calldataload(0) +// let t := calldataload(32) +// if sgt(sub(y, 1), y) +// { +// if 1 { sstore(0, 7) } +// if iszero(eq(y, t)) { if 1 { sstore(1, 7) } } +// } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/smod.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/smod.yul new file mode 100644 index 000000000..12f04c857 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/smod.yul @@ -0,0 +1,53 @@ +{ + // 7 % 5 == 2 + // 7 % -5 == 2 + // -7 % 5 == -2 + // -7 % -5 == -2 + // -5 % -5 == 0 + let x := calldataload(0) + let y := calldataload(32) + let result := smod(x, y) + if eq(x, 7) { + if eq(y, 5) { + if eq(result, 2) { sstore(0, 7)} + } + if eq(y, sub(0, 5)) { + if eq(result, 2) { sstore(0, 7)} + } + } + if eq(x, sub(0, 7)) { + if eq(y, 5) { + if eq(result, sub(0, 2)) { sstore(0, 7)} + } + if eq(y, sub(0, 5)) { + if eq(result, sub(0, 2)) { sstore(0, 7)} + } + } + if eq(x, sub(0, 5)) { + if eq(y, sub(0, 5)) { + if eq(result, 0) { sstore(0, 7)} + } + } +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := calldataload(0) +// let y := calldataload(32) +// let result := smod(x, y) +// if eq(x, 7) +// { +// if eq(y, 5) { if 1 { sstore(0, 7) } } +// if eq(y, sub(0, 5)) { if 1 { sstore(0, 7) } } +// } +// if eq(x, sub(0, 7)) +// { +// if eq(y, 5) { if 1 { sstore(0, 7) } } +// if eq(y, sub(0, 5)) { if 1 { sstore(0, 7) } } +// } +// if eq(x, sub(0, 5)) +// { +// if eq(y, sub(0, 5)) { if 1 { sstore(0, 7) } } +// } +// } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/smoke.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/smoke.yul new file mode 100644 index 000000000..6f860dc13 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/smoke.yul @@ -0,0 +1,5 @@ +{ } +// ---- +// step: reasoningBasedSimplifier +// +// { } diff --git a/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/wrapping.yul b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/wrapping.yul new file mode 100644 index 000000000..69f5c6769 --- /dev/null +++ b/test/libyul/yulOptimizerTests/reasoningBasedSimplifier/wrapping.yul @@ -0,0 +1,15 @@ +{ + let x := 7 + let y := 8 + if gt(sub(x, y), 20) { } + if eq(sub(x, y), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) {} +} +// ---- +// step: reasoningBasedSimplifier +// +// { +// let x := 7 +// let y := 8 +// if 1 { } +// if 1 { } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/cycle.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle.yul new file mode 100644 index 000000000..37da7f9b8 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle.yul @@ -0,0 +1,95 @@ +{ + mstore(0x40, memoryguard(128)) + sstore(0, g(sload(3))) + function g(x) -> v { + v := f() + } + function f() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + sstore(23, g(sload(42))) + } +} +// ---- +// step: stackLimitEvader +// +// { +// mstore(0x40, memoryguard(128)) +// sstore(0, g(sload(3))) +// function g(x) -> v +// { v := f() } +// function f() -> v_1 +// { +// let a1 := calldataload(mul(1, 4)) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// a1 := calldataload(mul(0, 4)) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, a1) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), a1) +// sstore(23, g(sload(42))) +// } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_after.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_after.yul new file mode 100644 index 000000000..4480d012e --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_after.yul @@ -0,0 +1,95 @@ +{ + mstore(0x40, memoryguard(128)) + sstore(0, f()) + function f() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + sstore(23, h()) + } + function h() -> v { + v := h() + } +} +// ---- +// step: stackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(0, f()) +// function f() -> v +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// sstore(23, h()) +// } +// function h() -> v_1 +// { v_1 := h() } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_after_2.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_after_2.yul new file mode 100644 index 000000000..4468165f1 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_after_2.yul @@ -0,0 +1,100 @@ +{ + mstore(0x40, memoryguard(128)) + sstore(0, f()) + function f() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + sstore(23, h()) + } + function h() -> v { + v := i() + } + function i() -> v { + v := h() + } +} +// ---- +// step: stackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(0, f()) +// function f() -> v +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// sstore(23, h()) +// } +// function h() -> v_1 +// { v_1 := i() } +// function i() -> v_2 +// { v_2 := h() } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before.yul new file mode 100644 index 000000000..e6819ea90 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before.yul @@ -0,0 +1,103 @@ +{ + mstore(0x40, memoryguard(128)) + sstore(0, g(sload(3))) + function g(x) -> v { + switch lt(x, 3) + case 0 { + v := f() + } + case 1 { + v := g(sub(x,1)) + } + } + function f() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + } +} +// ---- +// step: stackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(0, g(sload(3))) +// function g(x) -> v +// { +// switch lt(x, 3) +// case 0 { v := f() } +// case 1 { v := g(sub(x, 1)) } +// } +// function f() -> v_1 +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before_2.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before_2.yul new file mode 100644 index 000000000..a0259b180 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before_2.yul @@ -0,0 +1,108 @@ +{ + mstore(0x40, memoryguard(128)) + sstore(0, g(sload(3))) + function g(x) -> v { + switch lt(x, 3) + case 0 { + v := h(x) + } + case 1 { + v := g(sub(x,f())) + } + } + function h(x) -> v { + v := g(x) + } + function f() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + } +} +// ---- +// step: stackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(0, g(sload(3))) +// function g(x) -> v +// { +// switch lt(x, 3) +// case 0 { v := h(x) } +// case 1 { v := g(sub(x, f())) } +// } +// function h(x_1) -> v_2 +// { v_2 := g(x_1) } +// function f() -> v_3 +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before_after.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before_after.yul new file mode 100644 index 000000000..f5c068d5e --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/cycle_before_after.yul @@ -0,0 +1,110 @@ +{ + mstore(0x40, memoryguard(128)) + sstore(0, g(sload(0))) + function g(x) -> v { + switch lt(x, 3) + case 0 { + v := f() + } + case 1 { + v := g(sub(x,1)) + } + } + function f() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + sstore(23, h()) + } + function h() -> v { + v := h() + } +} +// ---- +// step: stackLimitEvader +// +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(0, g(sload(0))) +// function g(x) -> v +// { +// switch lt(x, 3) +// case 0 { v := f() } +// case 1 { v := g(sub(x, 1)) } +// } +// function f() -> v_1 +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// sstore(23, h()) +// } +// function h() -> v_2 +// { v_2 := h() } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/function_arg.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/function_arg.yul new file mode 100644 index 000000000..7bc4d2e80 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/function_arg.yul @@ -0,0 +1,88 @@ +{ + { + mstore(0x40, memoryguard(128)) + sstore(0, f(0)) + } + function f(a1) -> v { + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + } +} +// ---- +// step: stackLimitEvader +// +// { +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(0, f(0)) +// } +// function f(a1) -> v +// { +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, a1) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), a1) +// } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/stub.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/stub.yul new file mode 100644 index 000000000..ce12229b6 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/stub.yul @@ -0,0 +1,98 @@ +{ + { + mstore(0x40, memoryguard(128)) + sstore(g(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), f()) + } + function g(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16) -> v { + // Should be, but cannot yet be escalated. + v := b16 + } + function f() -> v{ + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + } +} +// ---- +// step: stackLimitEvader +// +// { +// { +// mstore(0x40, memoryguard(0xa0)) +// sstore(g(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), f()) +// } +// function g(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16) -> v +// { v := b16 } +// function f() -> v_1 +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(mul(4, 4)) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, 4), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/stackLimitEvader/tree.yul b/test/libyul/yulOptimizerTests/stackLimitEvader/tree.yul new file mode 100644 index 000000000..8407df5d0 --- /dev/null +++ b/test/libyul/yulOptimizerTests/stackLimitEvader/tree.yul @@ -0,0 +1,339 @@ +{ + { + mstore(0x40, memoryguard(128)) + sstore(23, f()) + } + function f() -> v{ + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(g()) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,h()), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + } + function g() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + v := i() + } + function h() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(10,4)) + a1 := calldataload(mul(0,4)) + a2 := calldataload(mul(1,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + let a18 := calldataload(mul(18,4)) + let a19 := calldataload(mul(19,4)) + sstore(0, add(a1, a2)) + sstore(mul(17,4), a19) + sstore(mul(17,4), a18) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + v := i() + } + function i() -> v { + let a1 := calldataload(mul(1,4)) + let a2 := calldataload(mul(2,4)) + let a3 := calldataload(mul(3,4)) + let a4 := calldataload(mul(4,4)) + let a5 := calldataload(mul(5,4)) + let a6 := calldataload(mul(6,4)) + let a7 := calldataload(mul(7,4)) + let a8 := calldataload(mul(8,4)) + let a9 := calldataload(mul(9,4)) + a1 := calldataload(mul(0,4)) + let a10 := calldataload(mul(10,4)) + let a11 := calldataload(mul(11,4)) + let a12 := calldataload(mul(12,4)) + let a13 := calldataload(mul(13,4)) + let a14 := calldataload(mul(14,4)) + let a15 := calldataload(mul(15,4)) + let a16 := calldataload(mul(16,4)) + let a17 := calldataload(mul(17,4)) + sstore(0, a1) + sstore(mul(17,4), a17) + sstore(mul(16,4), a16) + sstore(mul(15,4), a15) + sstore(mul(14,4), a14) + sstore(mul(13,4), a13) + sstore(mul(12,4), a12) + sstore(mul(11,4), a11) + sstore(mul(10,4), a10) + sstore(mul(9,4), a9) + sstore(mul(8,4), a8) + sstore(mul(7,4), a7) + sstore(mul(6,4), a6) + sstore(mul(5,4), a5) + sstore(mul(4,4), a4) + sstore(mul(3,4), a3) + sstore(mul(2,4), a2) + sstore(mul(1,4), a1) + v := sload(mul(42,8)) + } +} +// ---- +// step: stackLimitEvader +// +// { +// { +// mstore(0x40, memoryguard(0x0100)) +// sstore(23, f()) +// } +// function f() -> v +// { +// mstore(0x80, calldataload(mul(1, 4))) +// let a2 := calldataload(mul(2, 4)) +// let a3 := calldataload(mul(3, 4)) +// let a4 := calldataload(g()) +// let a5 := calldataload(mul(5, 4)) +// let a6 := calldataload(mul(6, 4)) +// let a7 := calldataload(mul(7, 4)) +// let a8 := calldataload(mul(8, 4)) +// let a9 := calldataload(mul(9, 4)) +// mstore(0x80, calldataload(mul(0, 4))) +// let a10 := calldataload(mul(10, 4)) +// let a11 := calldataload(mul(11, 4)) +// let a12 := calldataload(mul(12, 4)) +// let a13 := calldataload(mul(13, 4)) +// let a14 := calldataload(mul(14, 4)) +// let a15 := calldataload(mul(15, 4)) +// let a16 := calldataload(mul(16, 4)) +// let a17 := calldataload(mul(17, 4)) +// sstore(0, mload(0x80)) +// sstore(mul(17, 4), a17) +// sstore(mul(16, 4), a16) +// sstore(mul(15, 4), a15) +// sstore(mul(14, 4), a14) +// sstore(mul(13, 4), a13) +// sstore(mul(12, 4), a12) +// sstore(mul(11, 4), a11) +// sstore(mul(10, 4), a10) +// sstore(mul(9, 4), a9) +// sstore(mul(8, h()), a8) +// sstore(mul(7, 4), a7) +// sstore(mul(6, 4), a6) +// sstore(mul(5, 4), a5) +// sstore(mul(4, 4), a4) +// sstore(mul(3, 4), a3) +// sstore(mul(2, 4), a2) +// sstore(mul(1, 4), mload(0x80)) +// } +// function g() -> v_1 +// { +// mstore(0xc0, calldataload(mul(1, 4))) +// let a2_3 := calldataload(mul(2, 4)) +// let a3_4 := calldataload(mul(3, 4)) +// let a4_5 := calldataload(mul(4, 4)) +// let a5_6 := calldataload(mul(5, 4)) +// let a6_7 := calldataload(mul(6, 4)) +// let a7_8 := calldataload(mul(7, 4)) +// let a8_9 := calldataload(mul(8, 4)) +// let a9_10 := calldataload(mul(9, 4)) +// mstore(0xc0, calldataload(mul(0, 4))) +// let a10_11 := calldataload(mul(10, 4)) +// let a11_12 := calldataload(mul(11, 4)) +// let a12_13 := calldataload(mul(12, 4)) +// let a13_14 := calldataload(mul(13, 4)) +// let a14_15 := calldataload(mul(14, 4)) +// let a15_16 := calldataload(mul(15, 4)) +// let a16_17 := calldataload(mul(16, 4)) +// let a17_18 := calldataload(mul(17, 4)) +// sstore(0, mload(0xc0)) +// sstore(mul(17, 4), a17_18) +// sstore(mul(16, 4), a16_17) +// sstore(mul(15, 4), a15_16) +// sstore(mul(14, 4), a14_15) +// sstore(mul(13, 4), a13_14) +// sstore(mul(12, 4), a12_13) +// sstore(mul(11, 4), a11_12) +// sstore(mul(10, 4), a10_11) +// sstore(mul(9, 4), a9_10) +// sstore(mul(8, 4), a8_9) +// sstore(mul(7, 4), a7_8) +// sstore(mul(6, 4), a6_7) +// sstore(mul(5, 4), a5_6) +// sstore(mul(4, 4), a4_5) +// sstore(mul(3, 4), a3_4) +// sstore(mul(2, 4), a2_3) +// sstore(mul(1, 4), mload(0xc0)) +// v_1 := i() +// } +// function h() -> v_19 +// { +// mstore(0xa0, calldataload(mul(1, 4))) +// mstore(0xc0, calldataload(mul(2, 4))) +// let a3_22 := calldataload(mul(3, 4)) +// let a4_23 := calldataload(mul(4, 4)) +// let a5_24 := calldataload(mul(5, 4)) +// let a6_25 := calldataload(mul(6, 4)) +// let a7_26 := calldataload(mul(7, 4)) +// let a8_27 := calldataload(mul(8, 4)) +// let a9_28 := calldataload(mul(9, 4)) +// let a10_29 := calldataload(mul(10, 4)) +// let a11_30 := calldataload(mul(10, 4)) +// mstore(0xa0, calldataload(mul(0, 4))) +// mstore(0xc0, calldataload(mul(1, 4))) +// let a12_31 := calldataload(mul(12, 4)) +// let a13_32 := calldataload(mul(13, 4)) +// let a14_33 := calldataload(mul(14, 4)) +// let a15_34 := calldataload(mul(15, 4)) +// let a16_35 := calldataload(mul(16, 4)) +// let a17_36 := calldataload(mul(17, 4)) +// let a18 := calldataload(mul(18, 4)) +// let a19 := calldataload(mul(19, 4)) +// sstore(0, add(mload(0xa0), mload(0xc0))) +// sstore(mul(17, 4), a19) +// sstore(mul(17, 4), a18) +// sstore(mul(17, 4), a17_36) +// sstore(mul(16, 4), a16_35) +// sstore(mul(15, 4), a15_34) +// sstore(mul(14, 4), a14_33) +// sstore(mul(13, 4), a13_32) +// sstore(mul(12, 4), a12_31) +// sstore(mul(11, 4), a11_30) +// sstore(mul(10, 4), a10_29) +// sstore(mul(9, 4), a9_28) +// sstore(mul(8, 4), a8_27) +// sstore(mul(7, 4), a7_26) +// sstore(mul(6, 4), a6_25) +// sstore(mul(5, 4), a5_24) +// sstore(mul(4, 4), a4_23) +// sstore(mul(3, 4), a3_22) +// sstore(mul(2, 4), mload(0xc0)) +// sstore(mul(1, 4), mload(0xa0)) +// v_19 := i() +// } +// function i() -> v_37 +// { +// mstore(0xe0, calldataload(mul(1, 4))) +// let a2_39 := calldataload(mul(2, 4)) +// let a3_40 := calldataload(mul(3, 4)) +// let a4_41 := calldataload(mul(4, 4)) +// let a5_42 := calldataload(mul(5, 4)) +// let a6_43 := calldataload(mul(6, 4)) +// let a7_44 := calldataload(mul(7, 4)) +// let a8_45 := calldataload(mul(8, 4)) +// let a9_46 := calldataload(mul(9, 4)) +// mstore(0xe0, calldataload(mul(0, 4))) +// let a10_47 := calldataload(mul(10, 4)) +// let a11_48 := calldataload(mul(11, 4)) +// let a12_49 := calldataload(mul(12, 4)) +// let a13_50 := calldataload(mul(13, 4)) +// let a14_51 := calldataload(mul(14, 4)) +// let a15_52 := calldataload(mul(15, 4)) +// let a16_53 := calldataload(mul(16, 4)) +// let a17_54 := calldataload(mul(17, 4)) +// sstore(0, mload(0xe0)) +// sstore(mul(17, 4), a17_54) +// sstore(mul(16, 4), a16_53) +// sstore(mul(15, 4), a15_52) +// sstore(mul(14, 4), a14_51) +// sstore(mul(13, 4), a13_50) +// sstore(mul(12, 4), a12_49) +// sstore(mul(11, 4), a11_48) +// sstore(mul(10, 4), a10_47) +// sstore(mul(9, 4), a9_46) +// sstore(mul(8, 4), a8_45) +// sstore(mul(7, 4), a7_44) +// sstore(mul(6, 4), a6_43) +// sstore(mul(5, 4), a5_42) +// sstore(mul(4, 4), a4_41) +// sstore(mul(3, 4), a3_40) +// sstore(mul(2, 4), a2_39) +// sstore(mul(1, 4), mload(0xe0)) +// v_37 := sload(mul(42, 8)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/LiteralRematerialiser.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/LiteralRematerialiser.yul new file mode 100644 index 000000000..e11ea2a96 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/LiteralRematerialiser.yul @@ -0,0 +1,27 @@ +{ + let a := f(mload(1)) + let b := f(a) + sstore(a, b) + function f(x) -> y + { + // Test if LiteralRematerializer can convert `y` to `0` and therefore allowing us to + // rewrite the function f + if iszero(x) { revert(y, y)} + if iszero(add(x, 1)) { revert(y, y)} + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// let a := f_1(mload(1)) +// let b := f_1(a) +// sstore(a, b) +// function f(x) +// { +// if iszero(x) { revert(0, 0) } +// if iszero(add(x, 1)) { revert(0, 0) } +// } +// function f_1(x_2) -> y_3 +// { f(x_2) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/multiple_param.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/multiple_param.yul new file mode 100644 index 000000000..f2a036459 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/multiple_param.yul @@ -0,0 +1,24 @@ +{ + let d, e, i := f(1, 2, 3) + sstore(d, 0) + // b and x are unused + function f(a, b, c) -> x, y, z + { + y := mload(a) + z := mload(c) + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// let d, e, i := f_1(1, 2, 3) +// sstore(d, 0) +// function f(a, c) -> y, z +// { +// y := mload(a) +// z := mload(c) +// } +// function f_1(a_2, b_3, c_4) -> x_5, y_6, z_7 +// { y_6, z_7 := f(a_2, c_4) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/multiple_return.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/multiple_return.yul new file mode 100644 index 000000000..51612a699 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/multiple_return.yul @@ -0,0 +1,24 @@ +{ + let a, b, c := f(sload(0)) + sstore(a, 0) + // d is unused, x is unassigned + function f(d) -> x, y, z + { + y := mload(1) + z := mload(2) + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// let a, b, c := f_1(sload(0)) +// sstore(a, 0) +// function f() -> y, z +// { +// y := mload(1) +// z := mload(2) +// } +// function f_1(d_2) -> x_3, y_4, z_5 +// { y_4, z_5 := f() } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/nested_function.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/nested_function.yul new file mode 100644 index 000000000..d09ba44a6 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/nested_function.yul @@ -0,0 +1,56 @@ +// Test case to see if the step applies for nested functions. The function `j` has an unused argument. +{ + sstore(f(1), 0) + sstore(h(1), 0) + + function f(a) -> x + { + x := g(1) + x := add(x, 1) + function g(b) -> y + { + b := add(b, 1) + y := mload(b) + } + } + + function h(c) -> u + { + u := j(c) + // d is unused + function j(d) -> w + { + w := 13 + w := add(w, 1) + } + } + +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// sstore(f_1(1), 0) +// sstore(h(1), 0) +// function g(b) -> y +// { +// b := add(b, 1) +// y := mload(b) +// } +// function f() -> x +// { +// x := g(1) +// x := add(x, 1) +// } +// function f_1(a_3) -> x_4 +// { x_4 := f() } +// function j() -> w +// { +// w := 13 +// w := add(13, 1) +// } +// function j_2(d_5) -> w_6 +// { w_6 := j() } +// function h(c) -> u +// { u := j_2(c) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/nested_function_name_collision.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/nested_function_name_collision.yul new file mode 100644 index 000000000..8ce80f140 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/nested_function_name_collision.yul @@ -0,0 +1,52 @@ +// Test case where the name `g` occurs at two different places. Test to see if name-collision can +// cause issues. +{ + sstore(h(1), 0) + sstore(f(1), 0) + + function f(c) -> u + { + u := g(c) + function g(d) -> w + { + w := 13 + sstore(0, w) + } + } + + function h(c) -> u + { + u := g(c) + function g(d) -> w + { + w := 13 + sstore(0, w) + } + } + +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// sstore(h(1), 0) +// sstore(f(1), 0) +// function g() -> w +// { +// w := 13 +// sstore(0, 13) +// } +// function g_1(d_3) -> w_4 +// { w_4 := g() } +// function f(c) -> u +// { u := g_1(c) } +// function g_3() -> w_5 +// { +// w_5 := 13 +// sstore(0, 13) +// } +// function g_3_2(d_4_5) -> w_5_6 +// { w_5_6 := g_3() } +// function h(c_1) -> u_2 +// { u_2 := g_3_2(c_1) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/no_return.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/no_return.yul new file mode 100644 index 000000000..1cf059da2 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/no_return.yul @@ -0,0 +1,21 @@ +{ + f(1, 2) + function f(a, b) + { + sstore(a, 0) + a := add(a, 1) + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// f_1(1, 2) +// function f(a) +// { +// sstore(a, 0) +// a := add(a, 1) +// } +// function f_1(a_2, b_3) +// { f(a_2) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/no_unused.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/no_unused.yul new file mode 100644 index 000000000..ebbb70536 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/no_unused.yul @@ -0,0 +1,16 @@ +// A test where all parameters are used +{ + sstore(f(1), 0) + function f(a) -> x { x := a } + function g(b) -> y { y := g(b) } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// sstore(f(1), 0) +// function f(a) -> x +// { x := a } +// function g(b) -> y +// { y := g(b) } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/recursion.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/recursion.yul new file mode 100644 index 000000000..4a2c5b6cc --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/recursion.yul @@ -0,0 +1,21 @@ +{ + let a1, b1, c1 := f(1, 2, 3) + function f(a, b, c) -> x, y, z + { + x, y, z := f(1, 2, 3) + x := add(x, 1) + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// let a1, b1, c1 := f_1(1, 2, 3) +// function f() -> x, y, z +// { +// x, y, z := f_1(1, 2, 3) +// x := add(x, 1) +// } +// function f_1(a_2, b_3, c_4) -> x_5, y_6, z_7 +// { x_5, y_6, z_7 := f() } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/simple.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/simple.yul new file mode 100644 index 000000000..873eef977 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/simple.yul @@ -0,0 +1,21 @@ +{ + sstore(f(1), 0) + function f(x) -> y + { + let w := mload(1) + y := mload(w) + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// sstore(f_1(1), 0) +// function f() -> y +// { +// let w := mload(1) +// y := mload(w) +// } +// function f_1(x_2) -> y_3 +// { y_3 := f() } +// } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/smoke.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/smoke.yul new file mode 100644 index 000000000..1e0f9eb61 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/smoke.yul @@ -0,0 +1,5 @@ +{} +// ---- +// step: unusedFunctionParameterPruner +// +// { } diff --git a/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/too_many_arguments.yul b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/too_many_arguments.yul new file mode 100644 index 000000000..720489d57 --- /dev/null +++ b/test/libyul/yulOptimizerTests/unusedFunctionParameterPruner/too_many_arguments.yul @@ -0,0 +1,23 @@ +{ + let a, b := f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) + sstore(a, b) + function f(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18) -> y, z + { + y := mload(x3) + z := mload(x7) + } +} +// ---- +// step: unusedFunctionParameterPruner +// +// { +// let a, b := f_1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) +// sstore(a, b) +// function f(x3, x7) -> y, z +// { +// y := mload(x3) +// z := mload(x7) +// } +// function f_1(x1_2, x2_3, x3_4, x4_5, x5_6, x6_7, x7_8, x8_9, x9_10, x10_11, x11_12, x12_13, x13_14, x14_15, x15_16, x16_17, x17_18, x18_19) -> y_20, z_21 +// { y_20, z_21 := f(x3_4, x7_8) } +// } diff --git a/test/libyul/yulSyntaxTests/assign_from_stack.yul b/test/libyul/yulSyntaxTests/assign_from_stack.yul new file mode 100644 index 000000000..44f50ab5e --- /dev/null +++ b/test/libyul/yulSyntaxTests/assign_from_stack.yul @@ -0,0 +1,3 @@ +{ =: x:u256 } +// ---- +// ParserError 1856: (2-3): Literal or identifier expected. diff --git a/test/libyul/yulSyntaxTests/assignment.yul b/test/libyul/yulSyntaxTests/assignment.yul new file mode 100644 index 000000000..263e8e2dc --- /dev/null +++ b/test/libyul/yulSyntaxTests/assignment.yul @@ -0,0 +1,4 @@ +{ + let x:u256 := 2:u256 + let y:u256 := x +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/blocks.yul b/test/libyul/yulSyntaxTests/blocks.yul new file mode 100644 index 000000000..069dc463b --- /dev/null +++ b/test/libyul/yulSyntaxTests/blocks.yul @@ -0,0 +1,9 @@ +{ + let x:u256 := 7:u256 + { + let y:u256 := 3:u256 + } + { + let z:u256 := 2:u256 + } +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/builtin_types.yul b/test/libyul/yulSyntaxTests/builtin_types.yul new file mode 100644 index 000000000..ebf653b50 --- /dev/null +++ b/test/libyul/yulSyntaxTests/builtin_types.yul @@ -0,0 +1,15 @@ +{ + let x1:bool := true:bool + let x2:u8 := 1:u8 + let x3:s8 := 1:s8 + let x4:u32 := 1:u32 + let x5:s32 := 1:s32 + let x6:u64 := 1:u64 + let x7:s64 := 1:s64 + let x8:u128 := 1:u128 + let x9:s128 := 1:s128 + let x10:u256 := 1:u256 + let x11:s256 := 1:s256 +} +// ==== +// dialect: yul \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/empty_call.yul b/test/libyul/yulSyntaxTests/empty_call.yul new file mode 100644 index 000000000..30491c114 --- /dev/null +++ b/test/libyul/yulSyntaxTests/empty_call.yul @@ -0,0 +1,3 @@ +{ () } +// ---- +// ParserError 1856: (2-3): Literal or identifier expected. diff --git a/test/libyul/yulSyntaxTests/function_calls.yul b/test/libyul/yulSyntaxTests/function_calls.yul new file mode 100644 index 000000000..50238f798 --- /dev/null +++ b/test/libyul/yulSyntaxTests/function_calls.yul @@ -0,0 +1,8 @@ +{ + function f(a:u256) -> b:u256 {} + function g(a:u256, b:u256, c:u256) {} + function x() { + g(1:u256, 2:u256, f(3:u256)) + x() + } +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/function_definitions.yul b/test/libyul/yulSyntaxTests/function_definitions.yul new file mode 100644 index 000000000..ad22684b5 --- /dev/null +++ b/test/libyul/yulSyntaxTests/function_definitions.yul @@ -0,0 +1,4 @@ +{ + function f() { } + function g(a:u256) -> x:u256 { } +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/functions_multiple_args.yul b/test/libyul/yulSyntaxTests/functions_multiple_args.yul new file mode 100644 index 000000000..84468a4a9 --- /dev/null +++ b/test/libyul/yulSyntaxTests/functions_multiple_args.yul @@ -0,0 +1,4 @@ +{ + function f(a:u256, d:u256) { } + function g(a:u256, d:u256) -> x:u256, y:u256 { } +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/instructions.yul b/test/libyul/yulSyntaxTests/instructions.yul new file mode 100644 index 000000000..3d600812f --- /dev/null +++ b/test/libyul/yulSyntaxTests/instructions.yul @@ -0,0 +1,5 @@ +{ pop } +// ==== +// dialect: yul +// ---- +// ParserError 6913: (6-7): Call or assignment expected. diff --git a/test/libyul/yulSyntaxTests/number_literal_1.yul b/test/libyul/yulSyntaxTests/number_literal_1.yul new file mode 100644 index 000000000..456b9b9bd --- /dev/null +++ b/test/libyul/yulSyntaxTests/number_literal_1.yul @@ -0,0 +1 @@ +{ let x:u256 := 1:u256 } \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/number_literal_2.yul b/test/libyul/yulSyntaxTests/number_literal_2.yul new file mode 100644 index 000000000..94c5929b5 --- /dev/null +++ b/test/libyul/yulSyntaxTests/number_literal_2.yul @@ -0,0 +1,3 @@ +{ let x:u256 := .1:u256 } +// ---- +// ParserError 4828: (16-18): Invalid number literal. diff --git a/test/libyul/yulSyntaxTests/number_literal_3.yul b/test/libyul/yulSyntaxTests/number_literal_3.yul new file mode 100644 index 000000000..4dbb6879a --- /dev/null +++ b/test/libyul/yulSyntaxTests/number_literal_3.yul @@ -0,0 +1,3 @@ +{ let x:u256 := 1e5:u256 } +// ---- +// ParserError 4828: (16-19): Invalid number literal. diff --git a/test/libyul/yulSyntaxTests/number_literal_4.yul b/test/libyul/yulSyntaxTests/number_literal_4.yul new file mode 100644 index 000000000..7de784e88 --- /dev/null +++ b/test/libyul/yulSyntaxTests/number_literal_4.yul @@ -0,0 +1,3 @@ +{ let x:u256 := 67.235:u256 } +// ---- +// ParserError 4828: (16-22): Invalid number literal. diff --git a/test/libyul/yulSyntaxTests/number_literal_5.yul b/test/libyul/yulSyntaxTests/number_literal_5.yul new file mode 100644 index 000000000..df41e69ec --- /dev/null +++ b/test/libyul/yulSyntaxTests/number_literal_5.yul @@ -0,0 +1,3 @@ +{ let x:u256 := 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:u256 } +// ---- +// TypeError 6708: (16-88): Number literal too large (> 256 bits) diff --git a/test/libyul/yulSyntaxTests/optional_types.yul b/test/libyul/yulSyntaxTests/optional_types.yul new file mode 100644 index 000000000..c3433485b --- /dev/null +++ b/test/libyul/yulSyntaxTests/optional_types.yul @@ -0,0 +1,8 @@ +{ + let x := 1:u256 + let y:u256 := 1 + function f(a) {} + function g(a:u256) -> b {} +} +// ==== +// dialect: yul \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/period_in_identifier.yul b/test/libyul/yulSyntaxTests/period_in_identifier.yul new file mode 100644 index 000000000..1827e6ac2 --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_in_identifier.yul @@ -0,0 +1 @@ +{ let x.y:u256 := 2:u256 } \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/period_in_identifier_spaced_1.yul b/test/libyul/yulSyntaxTests/period_in_identifier_spaced_1.yul new file mode 100644 index 000000000..dc889a2fb --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_in_identifier_spaced_1.yul @@ -0,0 +1,3 @@ +{ let x. y:u256 } +// ---- +// ParserError 6913: (10-11): Call or assignment expected. diff --git a/test/libyul/yulSyntaxTests/period_in_identifier_spaced_2.yul b/test/libyul/yulSyntaxTests/period_in_identifier_spaced_2.yul new file mode 100644 index 000000000..5602cbceb --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_in_identifier_spaced_2.yul @@ -0,0 +1,3 @@ +{ let x .y:u256 } +// ---- +// ParserError 1856: (8-9): Literal or identifier expected. diff --git a/test/libyul/yulSyntaxTests/period_in_identifier_spaced_3.yul b/test/libyul/yulSyntaxTests/period_in_identifier_spaced_3.yul new file mode 100644 index 000000000..003341b33 --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_in_identifier_spaced_3.yul @@ -0,0 +1,3 @@ +{ let x . y:u256 } +// ---- +// ParserError 1856: (8-9): Literal or identifier expected. diff --git a/test/libyul/yulSyntaxTests/period_in_identifier_start.yul b/test/libyul/yulSyntaxTests/period_in_identifier_start.yul new file mode 100644 index 000000000..1c19455d6 --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_in_identifier_start.yul @@ -0,0 +1,4 @@ +{ + x.y(2:u256) + function x.y(a:u256) {} +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/period_in_identifier_start_with_comment.yul b/test/libyul/yulSyntaxTests/period_in_identifier_start_with_comment.yul new file mode 100644 index 000000000..ed47b09b7 --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_in_identifier_start_with_comment.yul @@ -0,0 +1,2 @@ +/// comment +{ x.y(2:u256) function x.y(a:u256) {} } \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/period_not_as_identifier_start.yul b/test/libyul/yulSyntaxTests/period_not_as_identifier_start.yul new file mode 100644 index 000000000..0002b76fd --- /dev/null +++ b/test/libyul/yulSyntaxTests/period_not_as_identifier_start.yul @@ -0,0 +1,3 @@ +{ let .y:u256 } +// ---- +// ParserError 2314: (6-7): Expected identifier but got '.' diff --git a/test/libyul/yulSyntaxTests/push.yul b/test/libyul/yulSyntaxTests/push.yul new file mode 100644 index 000000000..f3dab144d --- /dev/null +++ b/test/libyul/yulSyntaxTests/push.yul @@ -0,0 +1,3 @@ +{ 0x42:u256 } +// ---- +// ParserError 6913: (12-13): Call or assignment expected. diff --git a/test/libyul/yulSyntaxTests/smoke.yul b/test/libyul/yulSyntaxTests/smoke.yul new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/libyul/yulSyntaxTests/smoke.yul @@ -0,0 +1 @@ +{} diff --git a/test/libyul/yulSyntaxTests/token_as_identifier.yul b/test/libyul/yulSyntaxTests/token_as_identifier.yul new file mode 100644 index 000000000..4af1ea213 --- /dev/null +++ b/test/libyul/yulSyntaxTests/token_as_identifier.yul @@ -0,0 +1,8 @@ +{ + let return:u256 := 1:u256 + let byte:u256 := 1:u256 + let address:u256 := 1:u256 + let bool:u256 := 1:u256 +} +// ==== +// dialect: yul diff --git a/test/libyul/yulSyntaxTests/tuple_assignment.yul b/test/libyul/yulSyntaxTests/tuple_assignment.yul new file mode 100644 index 000000000..dbaccd097 --- /dev/null +++ b/test/libyul/yulSyntaxTests/tuple_assignment.yul @@ -0,0 +1,4 @@ +{ + function f() -> a:u256, b:u256, c:u256 {} + let x:u256, y:u256, z:u256 := f() +} \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/variable_declaration.yul b/test/libyul/yulSyntaxTests/variable_declaration.yul new file mode 100644 index 000000000..5e2ced34a --- /dev/null +++ b/test/libyul/yulSyntaxTests/variable_declaration.yul @@ -0,0 +1,3 @@ +{ let x:u256 := 7:u256 } +// ==== +// dialect: evmTyped diff --git a/test/libyul/yulSyntaxTests/variable_declaration_bool.yul b/test/libyul/yulSyntaxTests/variable_declaration_bool.yul new file mode 100644 index 000000000..8ef371eef --- /dev/null +++ b/test/libyul/yulSyntaxTests/variable_declaration_bool.yul @@ -0,0 +1,6 @@ +{ + let x:bool := true:bool + let y:bool := false:bool +} +// ==== +// dialect: evmTyped diff --git a/test/libyul/yulSyntaxTests/variable_declaration_complex.yul b/test/libyul/yulSyntaxTests/variable_declaration_complex.yul new file mode 100644 index 000000000..a1eab2fd6 --- /dev/null +++ b/test/libyul/yulSyntaxTests/variable_declaration_complex.yul @@ -0,0 +1,7 @@ +{ + function add(a:u256, b:u256) -> c:u256 {} + let y:u256 := 2:u256 + let x:u256 := add(7:u256, add(6:u256, y)) +} +// ==== +// dialect: yul \ No newline at end of file diff --git a/test/libyul/yulSyntaxTests/variable_declaration_empty.yul b/test/libyul/yulSyntaxTests/variable_declaration_empty.yul new file mode 100644 index 000000000..31f51090e --- /dev/null +++ b/test/libyul/yulSyntaxTests/variable_declaration_empty.yul @@ -0,0 +1 @@ +{ let x:u256 } \ No newline at end of file diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index c8add4ce7..dc0d58bce 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -31,7 +31,6 @@ add_executable(isoltest ../libsolidity/ABIJsonTest.cpp ../libsolidity/ASTJSONTest.cpp ../libsolidity/SMTCheckerTest.cpp - ../libsolidity/SMTCheckerJSONTest.cpp ../libyul/Common.cpp ../libyul/EwasmTranslationTest.cpp ../libyul/FunctionSideEffects.cpp diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index 84e2babe9..943832677 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -77,7 +77,7 @@ bool IsolTestOptions::parse(int _argc, char const* const* _argv) void IsolTestOptions::validate() const { - static std::string filterString{"[a-zA-Z1-9_/*]*"}; + static std::string filterString{"[a-zA-Z0-9_/*]*"}; static std::regex filterExpression{filterString}; assertThrow( regex_match(testFilter, filterExpression), diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 3bdb16b0f..0d6a92e5b 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -161,6 +161,7 @@ TestTool::Result TestTool::process() m_test = m_testCaseCreator(TestCase::Config{ m_path.string(), m_options.evmVersion(), + m_options.vmPaths, m_options.enforceViaYul }); if (m_test->shouldRun()) @@ -424,14 +425,19 @@ int main(int argc, char const *argv[]) auto& options = dynamic_cast(solidity::test::CommonOptions::get()); - bool disableSemantics = !solidity::test::EVMHost::getVM(options.evmonePath.string()); - if (disableSemantics) + bool disableSemantics = true; + try { - cout << "Unable to find " << solidity::test::evmoneFilename << ". Please provide the path using --evmonepath ." << endl; - cout << "You can download it at" << endl; - cout << solidity::test::evmoneDownloadLink << endl; - cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; + disableSemantics = !solidity::test::EVMHost::checkVmPaths(options.vmPaths); } + catch (std::runtime_error const& _exception) + { + cerr << "Error: " << _exception.what() << endl; + return 1; + } + + if (disableSemantics) + cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; TestStats global_stats{0, 0}; cout << "Running tests..." << endl << endl; @@ -472,7 +478,7 @@ int main(int argc, char const *argv[]) cout << "." << endl; if (disableSemantics) - cout << "\nNOTE: Skipped semantics tests because " << solidity::test::evmoneFilename << " could not be found.\n" << endl; + cout << "\nNOTE: Skipped semantics tests because no evmc vm could be found.\n" << endl; return global_stats ? 0 : 1; } diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index e4605d10f..a15c426dc 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -157,7 +158,7 @@ public: map const& extraOptions = { {'#', "quit"}, {',', "VarNameCleaner"}, - {';', "StackCompressor"}, + {';', "StackCompressor"} }; printUsageBanner(abbreviationMap, extraOptions, 4); diff --git a/test/yulPhaser/Chromosome.cpp b/test/yulPhaser/Chromosome.cpp index ecf754e8e..1f66398be 100644 --- a/test/yulPhaser/Chromosome.cpp +++ b/test/yulPhaser/Chromosome.cpp @@ -47,27 +47,22 @@ using namespace solidity::util; namespace solidity::phaser::test { +vector const ChrOmOsoMeSteps{ + ConditionalSimplifier::name, + FunctionHoister::name, + RedundantAssignEliminator::name, + ForLoopConditionOutOfBody::name, + Rematerialiser::name, + ForLoopConditionOutOfBody::name, + ExpressionSimplifier::name, + ForLoopInitRewriter::name, + LoopInvariantCodeMotion::name, + ExpressionInliner::name +}; + BOOST_AUTO_TEST_SUITE(Phaser, *boost::unit_test::label("nooptions")) BOOST_AUTO_TEST_SUITE(ChromosomeTest) -BOOST_AUTO_TEST_CASE(constructor_should_convert_from_string_to_optimisation_steps) -{ - vector expectedSteps{ - ConditionalSimplifier::name, - FunctionHoister::name, - RedundantAssignEliminator::name, - ForLoopConditionOutOfBody::name, - Rematerialiser::name, - ForLoopConditionOutOfBody::name, - ExpressionSimplifier::name, - ForLoopInitRewriter::name, - LoopInvariantCodeMotion::name, - ExpressionInliner::name - }; - - BOOST_TEST(Chromosome("ChrOmOsoMe").optimisationSteps() == expectedSteps); -} - BOOST_AUTO_TEST_CASE(makeRandom_should_return_different_chromosome_each_time) { SimulationRNG::reset(1); @@ -78,8 +73,8 @@ BOOST_AUTO_TEST_CASE(makeRandom_should_return_different_chromosome_each_time) BOOST_AUTO_TEST_CASE(makeRandom_should_use_every_possible_step_with_the_same_probability) { SimulationRNG::reset(1); - constexpr int samplesPerStep = 100; - constexpr double relativeTolerance = 0.01; + constexpr int samplesPerStep = 500; + constexpr double relativeTolerance = 0.02; map stepIndices = enumerateOptmisationSteps(); auto chromosome = Chromosome::makeRandom(stepIndices.size() * samplesPerStep); @@ -95,6 +90,11 @@ BOOST_AUTO_TEST_CASE(makeRandom_should_use_every_possible_step_with_the_same_pro BOOST_TEST(abs(meanSquaredError(samples, expectedValue) - variance) < variance * relativeTolerance); } +BOOST_AUTO_TEST_CASE(constructor_should_store_genes) +{ + BOOST_TEST(Chromosome("ChrOmOsoMe").genes() == "ChrOmOsoMe"); +} + BOOST_AUTO_TEST_CASE(constructor_should_store_optimisation_steps) { vector steps = { @@ -102,9 +102,8 @@ BOOST_AUTO_TEST_CASE(constructor_should_store_optimisation_steps) BlockFlattener::name, UnusedPruner::name, }; - Chromosome chromosome(steps); - BOOST_TEST(steps == chromosome.optimisationSteps()); + BOOST_TEST(Chromosome(steps).genes() == "tfu"); } BOOST_AUTO_TEST_CASE(constructor_should_allow_duplicate_steps) @@ -116,9 +115,18 @@ BOOST_AUTO_TEST_CASE(constructor_should_allow_duplicate_steps) UnusedPruner::name, BlockFlattener::name, }; - Chromosome chromosome(steps); - BOOST_TEST(steps == chromosome.optimisationSteps()); + BOOST_TEST(Chromosome(steps).genes() == "ttfuf"); + BOOST_TEST(Chromosome("ttfuf").genes() == "ttfuf"); +} + +BOOST_AUTO_TEST_CASE(constructor_should_allow_genes_that_do_not_correspond_to_any_step) +{ + assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0); + assert(OptimiserSuite::stepAbbreviationToNameMap().count('b') == 0); + + BOOST_TEST(Chromosome(".").genes() == "."); + BOOST_TEST(Chromosome("a..abatbb").genes() == "a..abatbb"); } BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_string_representation) @@ -130,14 +138,19 @@ BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_strin BOOST_TEST(chromosome.length() == allSteps.size()); BOOST_TEST(chromosome.optimisationSteps() == allSteps); - BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoighTLMrmVatud"); + BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoighTLMNRrmVatpud"); +} + +BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_optimisation_step_names) +{ + BOOST_TEST(Chromosome("ChrOmOsoMe").optimisationSteps() == ChrOmOsoMeSteps); } BOOST_AUTO_TEST_CASE(randomOptimisationStep_should_return_each_step_with_same_probability) { SimulationRNG::reset(1); - constexpr int samplesPerStep = 100; - constexpr double relativeTolerance = 0.01; + constexpr int samplesPerStep = 500; + constexpr double relativeTolerance = 0.02; map stepIndices = enumerateOptmisationSteps(); vector samples; @@ -151,6 +164,18 @@ BOOST_AUTO_TEST_CASE(randomOptimisationStep_should_return_each_step_with_same_pr BOOST_TEST(abs(meanSquaredError(samples, expectedValue) - variance) < variance * relativeTolerance); } +BOOST_AUTO_TEST_CASE(stepsToGenes_should_translate_optimisation_step_names_to_abbreviations) +{ + BOOST_TEST(Chromosome::stepsToGenes({}) == ""); + BOOST_TEST(Chromosome::stepsToGenes(ChrOmOsoMeSteps) == "ChrOmOsoMe"); +} + +BOOST_AUTO_TEST_CASE(genesToSteps_should_translate_optimisation_step_abbreviations_to_names) +{ + BOOST_TEST(Chromosome::genesToSteps("") == vector{}); + BOOST_TEST(Chromosome::genesToSteps("ChrOmOsoMe") == ChrOmOsoMeSteps); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp index cfac86db0..16d5cc654 100644 --- a/test/yulPhaser/GeneticAlgorithms.cpp +++ b/test/yulPhaser/GeneticAlgorithms.cpp @@ -213,8 +213,7 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossove BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(ClassicGeneticAlgorithmTest) -// FIXME: This test runs *very* slowly (tens of seconds). Investigate, fix and re-enable. -BOOST_FIXTURE_TEST_CASE(runNextRound_should_select_individuals_with_probability_proportional_to_fitness, ClassicGeneticAlgorithmFixture, *boost::unit_test::disabled()) +BOOST_FIXTURE_TEST_CASE(runNextRound_should_select_individuals_with_probability_proportional_to_fitness, ClassicGeneticAlgorithmFixture) { constexpr double relativeTolerance = 0.1; constexpr size_t populationSize = 1000; @@ -255,8 +254,7 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_select_individuals_with_probability_ BOOST_TEST(abs(meanSquaredError(newFitness, expectedValue) - variance) < variance * relativeTolerance); } -// FIXME: This test runs *very* slowly (tens of seconds). Investigate, fix and re-enable. -BOOST_FIXTURE_TEST_CASE(runNextRound_should_select_only_individuals_existing_in_the_original_population, ClassicGeneticAlgorithmFixture, *boost::unit_test::disabled()) +BOOST_FIXTURE_TEST_CASE(runNextRound_should_select_only_individuals_existing_in_the_original_population, ClassicGeneticAlgorithmFixture) { constexpr size_t populationSize = 1000; auto population = Population::makeRandom(m_fitnessMetric, populationSize, 1, 10); @@ -300,8 +298,7 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_crossover, ClassicGeneticAlgorith BOOST_TEST(totalCrossed >= 2); } -// FIXME: This test runs *very* slowly (tens of seconds). Investigate, fix and re-enable. -BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_mutation, ClassicGeneticAlgorithmFixture, *boost::unit_test::disabled()) +BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_mutation, ClassicGeneticAlgorithmFixture) { m_options.mutationChance = 0.6; ClassicGeneticAlgorithm algorithm(m_options); @@ -330,8 +327,7 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_mutation, ClassicGeneticAlgorithm BOOST_TEST(abs(meanSquaredError(bernoulliTrials, expectedValue) - variance) < variance * relativeTolerance); } -// FIXME: This test runs *very* slowly (tens of seconds). Investigate, fix and re-enable. -BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_deletion, ClassicGeneticAlgorithmFixture, *boost::unit_test::disabled()) +BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_deletion, ClassicGeneticAlgorithmFixture) { m_options.deletionChance = 0.6; ClassicGeneticAlgorithm algorithm(m_options); @@ -360,8 +356,7 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_deletion, ClassicGeneticAlgorithm BOOST_TEST(abs(meanSquaredError(bernoulliTrials, expectedValue) - variance) < variance * relativeTolerance); } -// FIXME: This test runs *very* slowly (tens of seconds). Investigate, fix and re-enable. -BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_addition, ClassicGeneticAlgorithmFixture, *boost::unit_test::disabled()) +BOOST_FIXTURE_TEST_CASE(runNextRound_should_do_addition, ClassicGeneticAlgorithmFixture) { m_options.additionChance = 0.6; ClassicGeneticAlgorithm algorithm(m_options); diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp index dfdd600a3..a8fa053a2 100644 --- a/test/yulPhaser/Mutations.cpp +++ b/test/yulPhaser/Mutations.cpp @@ -22,14 +22,17 @@ #include #include +#include #include +#include #include #include using namespace std; using namespace solidity::util; +using namespace solidity::yul; namespace solidity::phaser::test { @@ -40,19 +43,32 @@ BOOST_AUTO_TEST_SUITE(GeneRandomisationTest) BOOST_AUTO_TEST_CASE(geneRandomisation_should_iterate_over_genes_and_replace_them_with_random_ones_with_given_probability) { - Chromosome chromosome("fcCUnDvejs"); - function mutation01 = geneRandomisation(0.1); - function mutation05 = geneRandomisation(0.5); - function mutation10 = geneRandomisation(1.0); + size_t constexpr inputLength = 1000; + double constexpr tolerance = 0.05; + + // Use genes that do not represent valid step abbreviations to be able to easily spot added steps. + assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0); + Chromosome input = Chromosome(string(inputLength, '.')); SimulationRNG::reset(1); - BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 2); - BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 5); - BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 7); - SimulationRNG::reset(2); - BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 1); - BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 3); - BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 9); + for (size_t randomisationChancePercent = 20; randomisationChancePercent <= 100; randomisationChancePercent += 20) + { + double const randomisationChance = (randomisationChancePercent / 100.0); + + Chromosome output = geneRandomisation(randomisationChance)(input); + string outputGenes = output.genes(); + BOOST_REQUIRE(output.length() == input.length()); + + double const expectedValue = randomisationChance; + double const variance = randomisationChance * (1 - randomisationChance); + double const randomisedGeneCount = input.length() - static_cast(count(outputGenes.begin(), outputGenes.end(), '.')); + double const squaredError = + (inputLength - randomisedGeneCount) * expectedValue * expectedValue + + randomisedGeneCount * (1 - expectedValue) * (1 - expectedValue); + + BOOST_TEST(abs(randomisedGeneCount / inputLength - expectedValue) < tolerance); + BOOST_TEST(abs(squaredError / inputLength - variance) < tolerance); + } } BOOST_AUTO_TEST_CASE(geneRandomisation_should_return_identical_chromosome_if_probability_is_zero) @@ -65,17 +81,33 @@ BOOST_AUTO_TEST_CASE(geneRandomisation_should_return_identical_chromosome_if_pro BOOST_AUTO_TEST_CASE(geneDeletion_should_iterate_over_genes_and_delete_them_with_given_probability) { - Chromosome chromosome("fcCUnDvejs"); - function mutation01 = geneDeletion(0.1); - function mutation05 = geneDeletion(0.5); + size_t constexpr inputLength = 1000; + double constexpr tolerance = 0.05; + + // Use genes that do not represent valid step abbreviations to be able to easily spot added steps. + assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0); + Chromosome input = Chromosome(string(inputLength, '.')); SimulationRNG::reset(1); - // fcCUnDvejs - BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcCU Dvejs"))); - BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" D ejs"))); - SimulationRNG::reset(2); - BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcUnDvejs"))); - BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" Un s"))); + for (size_t deletionChancePercent = 20; deletionChancePercent < 100; deletionChancePercent += 20) + { + double const deletionChance = (deletionChancePercent / 100.0); + + Chromosome output = geneDeletion(deletionChance)(input); + string outputGenes = output.genes(); + BOOST_REQUIRE(output.length() <= input.length()); + BOOST_REQUIRE(static_cast(count(outputGenes.begin(), outputGenes.end(), '.')) == output.length()); + + double const expectedValue = deletionChance; + double const variance = deletionChance * (1 - deletionChance); + double const deletedGeneCount = input.length() - output.length(); + double const squaredError = + (inputLength - deletedGeneCount) * expectedValue * expectedValue + + deletedGeneCount * (1 - expectedValue) * (1 - expectedValue); + + BOOST_TEST(abs(deletedGeneCount / inputLength - expectedValue) < tolerance); + BOOST_TEST(abs(squaredError / inputLength - variance) < tolerance); + } } BOOST_AUTO_TEST_CASE(geneDeletion_should_return_identical_chromosome_if_probability_is_zero) @@ -96,17 +128,37 @@ BOOST_AUTO_TEST_CASE(geneDeletion_should_delete_all_genes_if_probability_is_one) BOOST_AUTO_TEST_CASE(geneAddition_should_iterate_over_gene_positions_and_insert_new_genes_with_given_probability) { - Chromosome chromosome("fcCUnDvejs"); - function mutation01 = geneAddition(0.1); - function mutation05 = geneAddition(0.5); + size_t constexpr inputLength = 1000; + double constexpr tolerance = 0.05; + size_t constexpr maxAdditions = inputLength + 1; + + // Use genes that do not represent valid step abbreviations to be able to easily spot added steps. + assert(OptimiserSuite::stepAbbreviationToNameMap().count('.') == 0); + Chromosome input = Chromosome(string(inputLength, '.')); SimulationRNG::reset(1); - // f c C U n D v e j s - BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f c C UC n D v e jx s"))); // 20% more - BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("j f cu C U ne D v eI j sf"))); // 50% more - SimulationRNG::reset(2); - BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f cu C U n D v e j s"))); // 10% more - BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("L f ce Cv U n D v e jO s"))); // 40% more + for (size_t additionChancePercent = 20; additionChancePercent < 100; additionChancePercent += 20) + { + double const additionChance = (additionChancePercent / 100.0); + + Chromosome output = geneAddition(additionChance)(input); + BOOST_REQUIRE(output.length() >= input.length()); + BOOST_REQUIRE(output.length() <= inputLength + maxAdditions); + + string_view outputGenes = output.genes(); + size_t preservedGeneCount = static_cast(count(outputGenes.begin(), outputGenes.end(), '.')); + BOOST_REQUIRE(preservedGeneCount == input.length()); + + double const expectedValue = additionChance; + double const variance = additionChance * (1 - additionChance); + double const addedGeneCount = (output.length() - preservedGeneCount); + double const squaredError = + (maxAdditions - addedGeneCount) * expectedValue * expectedValue + + addedGeneCount * (1 - expectedValue) * (1 - expectedValue); + + BOOST_TEST(abs(addedGeneCount / maxAdditions - expectedValue) < tolerance); + BOOST_TEST(abs(squaredError / maxAdditions - variance) < tolerance); + } } BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position) @@ -117,12 +169,7 @@ BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position Chromosome mutatedChromosome = mutation(chromosome); BOOST_TEST(mutatedChromosome.length() > chromosome.length()); - - vector suffix( - mutatedChromosome.optimisationSteps().end() - static_cast(chromosome.length()), - mutatedChromosome.optimisationSteps().end() - ); - BOOST_TEST(suffix == chromosome.optimisationSteps()); + BOOST_TEST(boost::ends_with(mutatedChromosome.genes(), chromosome.genes())); } BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_after_last_position) @@ -133,12 +180,7 @@ BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_after_last_position) Chromosome mutatedChromosome = mutation(chromosome); BOOST_TEST(mutatedChromosome.length() > chromosome.length()); - - vector prefix( - mutatedChromosome.optimisationSteps().begin(), - mutatedChromosome.optimisationSteps().begin() + static_cast(chromosome.length()) - ); - BOOST_TEST(prefix == chromosome.optimisationSteps()); + BOOST_TEST(boost::starts_with(mutatedChromosome.genes(), chromosome.genes())); } BOOST_AUTO_TEST_CASE(geneAddition_should_return_identical_chromosome_if_probability_is_zero) @@ -218,10 +260,11 @@ BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_second_mutation_i BOOST_AUTO_TEST_CASE(mutationSequence_should_apply_all_mutations) { Chromosome chromosome("aaaaa"); + vector steps = Chromosome::genesToSteps("gfc"); function mutation = mutationSequence({ - geneSubstitution(3, Chromosome("g").optimisationSteps()[0]), - geneSubstitution(2, Chromosome("f").optimisationSteps()[0]), - geneSubstitution(1, Chromosome("c").optimisationSteps()[0]), + geneSubstitution(3, steps[0]), + geneSubstitution(2, steps[1]), + geneSubstitution(1, steps[2]), }); BOOST_TEST(mutation(chromosome) == Chromosome("acfga")); @@ -230,11 +273,12 @@ BOOST_AUTO_TEST_CASE(mutationSequence_should_apply_all_mutations) BOOST_AUTO_TEST_CASE(mutationSequence_apply_mutations_in_the_order_they_are_given) { Chromosome chromosome("aa"); + vector steps = Chromosome::genesToSteps("gcfo"); function mutation = mutationSequence({ - geneSubstitution(0, Chromosome("g").optimisationSteps()[0]), - geneSubstitution(1, Chromosome("c").optimisationSteps()[0]), - geneSubstitution(0, Chromosome("f").optimisationSteps()[0]), - geneSubstitution(1, Chromosome("o").optimisationSteps()[0]), + geneSubstitution(0, steps[0]), + geneSubstitution(1, steps[1]), + geneSubstitution(0, steps[2]), + geneSubstitution(1, steps[3]), }); BOOST_TEST(mutation(chromosome) == Chromosome("fo")); diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index 673c43824..013f3a9e0 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE(build_should_apply_prefix) CharStream nestedSource("{{{let x:= 1}}}", ""); Program nestedProgram = get(Program::load(nestedSource)); Program flatProgram = get(Program::load(nestedSource)); - flatProgram.optimise(Chromosome("f").optimisationSteps()); + flatProgram.optimise(Chromosome::genesToSteps("f")); assert(toString(nestedProgram) != toString(flatProgram)); { diff --git a/test/yulPhaser/ProgramCache.cpp b/test/yulPhaser/ProgramCache.cpp index 7fb74fca9..3a84aad67 100644 --- a/test/yulPhaser/ProgramCache.cpp +++ b/test/yulPhaser/ProgramCache.cpp @@ -53,7 +53,7 @@ protected: Program optimisedProgram(Program _program, string _abbreviatedOptimisationSteps) const { Program result = move(_program); - result.optimise(Chromosome(_abbreviatedOptimisationSteps).optimisationSteps()); + result.optimise(Chromosome::genesToSteps(_abbreviatedOptimisationSteps)); return result; } diff --git a/tools/solidityUpgrade/Upgrade060.cpp b/tools/solidityUpgrade/Upgrade060.cpp index 58aa94d15..a5d2f0af6 100644 --- a/tools/solidityUpgrade/Upgrade060.cpp +++ b/tools/solidityUpgrade/Upgrade060.cpp @@ -100,7 +100,7 @@ inline string appendVirtual(FunctionDefinition const& _function) void AbstractContract::endVisit(ContractDefinition const& _contract) { - bool isFullyImplemented = _contract.annotation().unimplementedDeclarations.empty(); + bool isFullyImplemented = _contract.annotation().unimplementedDeclarations->empty(); if ( !isFullyImplemented && diff --git a/tools/yulPhaser/Chromosome.cpp b/tools/yulPhaser/Chromosome.cpp index 453c62d39..687c669da 100644 --- a/tools/yulPhaser/Chromosome.cpp +++ b/tools/yulPhaser/Chromosome.cpp @@ -37,12 +37,6 @@ ostream& operator<<(ostream& _stream, Chromosome const& _chromosome); } -Chromosome::Chromosome(string const& _optimisationSteps) -{ - for (char abbreviation: _optimisationSteps) - m_optimisationSteps.push_back(OptimiserSuite::stepAbbreviationToNameMap().at(abbreviation)); -} - Chromosome Chromosome::makeRandom(size_t _length) { vector steps; @@ -54,10 +48,7 @@ Chromosome Chromosome::makeRandom(size_t _length) ostream& phaser::operator<<(ostream& _stream, Chromosome const& _chromosome) { - for (auto const& stepName: _chromosome.m_optimisationSteps) - _stream << OptimiserSuite::stepNameToAbbreviationMap().at(stepName); - - return _stream; + return _stream << _chromosome.m_genes; } vector Chromosome::allStepNames() @@ -75,3 +66,26 @@ string const& Chromosome::randomOptimisationStep() return stepNames[SimulationRNG::uniformInt(0, stepNames.size() - 1)]; } + +char Chromosome::randomGene() +{ + return OptimiserSuite::stepNameToAbbreviationMap().at(randomOptimisationStep()); +} + +string Chromosome::stepsToGenes(vector const& _optimisationSteps) +{ + string genes; + for (string const& stepName: _optimisationSteps) + genes.push_back(OptimiserSuite::stepNameToAbbreviationMap().at(stepName)); + + return genes; +} + +vector Chromosome::genesToSteps(string const& _genes) +{ + vector steps; + for (char abbreviation: _genes) + steps.push_back(OptimiserSuite::stepAbbreviationToNameMap().at(abbreviation)); + + return steps; +} diff --git a/tools/yulPhaser/Chromosome.h b/tools/yulPhaser/Chromosome.h index 95f3ae58e..96477086f 100644 --- a/tools/yulPhaser/Chromosome.h +++ b/tools/yulPhaser/Chromosome.h @@ -42,24 +42,32 @@ class Chromosome public: Chromosome() = default; explicit Chromosome(std::vector _optimisationSteps): - m_optimisationSteps(std::move(_optimisationSteps)) {} - explicit Chromosome(std::string const& _optimisationSteps); + m_genes(stepsToGenes(_optimisationSteps)) {} + explicit Chromosome(std::string _genes): + // NOTE: We don't validate the genes - they're only checked at the point of conversion to + // actual optimisation steps names. This is very convenient in mutation tests. + m_genes(std::move(_genes)) {} static Chromosome makeRandom(size_t _length); - size_t length() const { return m_optimisationSteps.size(); } - std::vector const& optimisationSteps() const { return m_optimisationSteps; } + size_t length() const { return m_genes.size(); } + std::string const& genes() const { return m_genes; } + + std::vector optimisationSteps() const { return genesToSteps(m_genes); } friend std::ostream& operator<<(std::ostream& _stream, Chromosome const& _chromosome); - bool operator==(Chromosome const& _other) const { return m_optimisationSteps == _other.m_optimisationSteps; } + bool operator==(Chromosome const& _other) const { return m_genes == _other.m_genes; } bool operator!=(Chromosome const& _other) const { return !(*this == _other); } static std::string const& randomOptimisationStep(); + static char randomGene(); + static std::string stepsToGenes(std::vector const& _optimisationSteps); + static std::vector genesToSteps(std::string const& _genes); private: static std::vector allStepNames(); - std::vector m_optimisationSteps; + std::string m_genes; }; } diff --git a/tools/yulPhaser/Mutations.cpp b/tools/yulPhaser/Mutations.cpp index f9d51744e..3e3e91b28 100644 --- a/tools/yulPhaser/Mutations.cpp +++ b/tools/yulPhaser/Mutations.cpp @@ -36,15 +36,15 @@ function phaser::geneRandomisation(double _chance) { return [=](Chromosome const& _chromosome) { - vector optimisationSteps; - for (auto const& step: _chromosome.optimisationSteps()) - optimisationSteps.push_back( + string genes; + for (char gene: _chromosome.genes()) + genes.push_back( SimulationRNG::bernoulliTrial(_chance) ? - Chromosome::randomOptimisationStep() : - step + Chromosome::randomGene() : + gene ); - return Chromosome(move(optimisationSteps)); + return Chromosome(move(genes)); }; } @@ -52,12 +52,12 @@ function phaser::geneDeletion(double _chance) { return [=](Chromosome const& _chromosome) { - vector optimisationSteps; - for (auto const& step: _chromosome.optimisationSteps()) + string genes; + for (char gene: _chromosome.genes()) if (!SimulationRNG::bernoulliTrial(_chance)) - optimisationSteps.push_back(step); + genes.push_back(gene); - return Chromosome(move(optimisationSteps)); + return Chromosome(move(genes)); }; } @@ -65,19 +65,19 @@ function phaser::geneAddition(double _chance) { return [=](Chromosome const& _chromosome) { - vector optimisationSteps; + string genes; if (SimulationRNG::bernoulliTrial(_chance)) - optimisationSteps.push_back(Chromosome::randomOptimisationStep()); + genes.push_back(Chromosome::randomGene()); - for (auto const& step: _chromosome.optimisationSteps()) + for (char gene: _chromosome.genes()) { - optimisationSteps.push_back(step); + genes.push_back(gene); if (SimulationRNG::bernoulliTrial(_chance)) - optimisationSteps.push_back(Chromosome::randomOptimisationStep()); + genes.push_back(Chromosome::randomGene()); } - return Chromosome(move(optimisationSteps)); + return Chromosome(move(genes)); }; } @@ -120,19 +120,14 @@ ChromosomePair fixedPointSwap( assert(_crossoverPoint <= _chromosome1.length()); assert(_crossoverPoint <= _chromosome2.length()); - auto begin1 = _chromosome1.optimisationSteps().begin(); - auto begin2 = _chromosome2.optimisationSteps().begin(); - auto end1 = _chromosome1.optimisationSteps().end(); - auto end2 = _chromosome2.optimisationSteps().end(); - return { Chromosome( - vector(begin1, begin1 + static_cast(_crossoverPoint)) + - vector(begin2 + static_cast(_crossoverPoint), end2) + _chromosome1.genes().substr(0, _crossoverPoint) + + _chromosome2.genes().substr(_crossoverPoint, _chromosome2.length() - _crossoverPoint) ), Chromosome( - vector(begin2, begin2 + static_cast(_crossoverPoint)) + - vector(begin1 + static_cast(_crossoverPoint), end1) + _chromosome2.genes().substr(0, _crossoverPoint) + + _chromosome1.genes().substr(_crossoverPoint, _chromosome1.length() - _crossoverPoint) ), }; } @@ -197,24 +192,19 @@ ChromosomePair fixedTwoPointSwap( assert(_crossoverPoint2 <= _chromosome1.length()); assert(_crossoverPoint2 <= _chromosome2.length()); - auto lowPoint = static_cast(min(_crossoverPoint1, _crossoverPoint2)); - auto highPoint = static_cast(max(_crossoverPoint1, _crossoverPoint2)); - - auto begin1 = _chromosome1.optimisationSteps().begin(); - auto begin2 = _chromosome2.optimisationSteps().begin(); - auto end1 = _chromosome1.optimisationSteps().end(); - auto end2 = _chromosome2.optimisationSteps().end(); + size_t lowPoint = min(_crossoverPoint1, _crossoverPoint2); + size_t highPoint = max(_crossoverPoint1, _crossoverPoint2); return { Chromosome( - vector(begin1, begin1 + lowPoint) + - vector(begin2 + lowPoint, begin2 + highPoint) + - vector(begin1 + highPoint, end1) + _chromosome1.genes().substr(0, lowPoint) + + _chromosome2.genes().substr(lowPoint, highPoint - lowPoint) + + _chromosome1.genes().substr(highPoint, _chromosome1.length() - highPoint) ), Chromosome( - vector(begin2, begin2 + lowPoint) + - vector(begin1 + lowPoint, begin1 + highPoint) + - vector(begin2 + highPoint, end2) + _chromosome2.genes().substr(0, lowPoint) + + _chromosome1.genes().substr(lowPoint, highPoint - lowPoint) + + _chromosome2.genes().substr(highPoint, _chromosome2.length() - highPoint) ), }; } @@ -258,42 +248,37 @@ namespace ChromosomePair uniformSwap(Chromosome const& _chromosome1, Chromosome const& _chromosome2, double _swapChance) { - vector steps1; - vector steps2; + string steps1; + string steps2; size_t minLength = min(_chromosome1.length(), _chromosome2.length()); for (size_t i = 0; i < minLength; ++i) if (SimulationRNG::bernoulliTrial(_swapChance)) { - steps1.push_back(_chromosome2.optimisationSteps()[i]); - steps2.push_back(_chromosome1.optimisationSteps()[i]); + steps1.push_back(_chromosome2.genes()[i]); + steps2.push_back(_chromosome1.genes()[i]); } else { - steps1.push_back(_chromosome1.optimisationSteps()[i]); - steps2.push_back(_chromosome2.optimisationSteps()[i]); + steps1.push_back(_chromosome1.genes()[i]); + steps2.push_back(_chromosome2.genes()[i]); } - auto begin1 = _chromosome1.optimisationSteps().begin(); - auto begin2 = _chromosome2.optimisationSteps().begin(); - auto end1 = _chromosome1.optimisationSteps().end(); - auto end2 = _chromosome2.optimisationSteps().end(); - bool swapTail = SimulationRNG::bernoulliTrial(_swapChance); if (_chromosome1.length() > minLength) { if (swapTail) - steps2.insert(steps2.end(), begin1 + static_cast(minLength), end1); + steps2 += _chromosome1.genes().substr(minLength, _chromosome1.length() - minLength); else - steps1.insert(steps1.end(), begin1 + static_cast(minLength), end1); + steps1 += _chromosome1.genes().substr(minLength, _chromosome1.length() - minLength); } if (_chromosome2.length() > minLength) { if (swapTail) - steps1.insert(steps1.end(), begin2 + static_cast(minLength), end2); + steps1 += _chromosome2.genes().substr(minLength, _chromosome2.length() - minLength); else - steps2.insert(steps2.end(), begin2 + static_cast(minLength), end2); + steps2 += _chromosome2.genes().substr(minLength, _chromosome2.length() - minLength); } return {Chromosome(steps1), Chromosome(steps2)}; diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index c4b506369..1dba2e2fd 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -54,7 +54,7 @@ bool phaser::isFitter(Individual const& a, Individual const& b) return ( (a.fitness < b.fitness) || (a.fitness == b.fitness && a.chromosome.length() < b.chromosome.length()) || - (a.fitness == b.fitness && a.chromosome.length() == b.chromosome.length() && toString(a.chromosome) < toString(b.chromosome)) + (a.fitness == b.fitness && a.chromosome.length() == b.chromosome.length() && a.chromosome.genes() < b.chromosome.genes()) ); }