mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12376 from ethereum/develop
Merge `develop` into `breaking`
This commit is contained in:
commit
0bbf58ec5e
@ -20,7 +20,7 @@ cd build
|
|||||||
$boost_dir=(Resolve-Path $PSScriptRoot\..\deps\boost\lib\cmake\Boost-*)
|
$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" -DUSE_Z3=OFF ..
|
..\deps\cmake\bin\cmake -G "Visual Studio 16 2019" -DBoost_DIR="$boost_dir\" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_INSTALL_PREFIX="$PSScriptRoot\..\upload" -DUSE_Z3=OFF ..
|
||||||
if ( -not $? ) { throw "CMake configure failed." }
|
if ( -not $? ) { throw "CMake configure failed." }
|
||||||
msbuild solidity.sln /p:Configuration=Release /m:5 /v:minimal
|
msbuild solidity.sln /p:Configuration=Release /m:10 /v:minimal
|
||||||
if ( -not $? ) { throw "Build failed." }
|
if ( -not $? ) { throw "Build failed." }
|
||||||
..\deps\cmake\bin\cmake --build . -j 5 --target install --config Release
|
..\deps\cmake\bin\cmake --build . -j 10 --target install --config Release
|
||||||
if ( -not $? ) { throw "Install target failed." }
|
if ( -not $? ) { throw "Install target failed." }
|
||||||
|
@ -9,20 +9,20 @@ version: 2.1
|
|||||||
parameters:
|
parameters:
|
||||||
ubuntu-2004-docker-image:
|
ubuntu-2004-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-8
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-9
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:9c3cdfc1d573d1ca3edacd892590a9a83487a1f746a6ca2093d7e009818c5179"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:3d8a912e8e78e98cd217955d06d98608ad60adc67728d4c3a569991235fa1abb"
|
||||||
ubuntu-2004-clang-docker-image:
|
ubuntu-2004-clang-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-8
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-9
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:61232feea23c8c57e82cf5fae890f8b86bbec353cdc04f2fcba383ca589e1d8b"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:a1ba002cae17279d1396a898b04e4e9c45602ad881295db3e2f484a7e24f6f43"
|
||||||
ubuntu-1604-clang-ossfuzz-docker-image:
|
ubuntu-1604-clang-ossfuzz-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-13
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-14
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:c26a7ffc9fc243a4ec3105b9dc1edcdd964ad0e9665c83172b7ebda74bbf3021"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:f353823cce2f6cd2f9f1459d86cd76fdfc551a0261d87626615ea6c1d8f90587"
|
||||||
emscripten-docker-image:
|
emscripten-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:emscripten-7
|
# solbuildpackpusher/solidity-buildpack-deps:emscripten-8
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:9ffcd0944433fe100e9433f2aa9ba5c21e096e758ad8a05a4a76feaed3d1f463"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:842d6074e0e7e5355c89122c1cafc1fdb59696596750e7d56e5f35c0d883ad59"
|
||||||
evm-version:
|
evm-version:
|
||||||
type: string
|
type: string
|
||||||
default: london
|
default: london
|
||||||
@ -44,10 +44,17 @@ commands:
|
|||||||
name: "Gitter notification"
|
name: "Gitter notification"
|
||||||
when: << parameters.condition >>
|
when: << parameters.condition >>
|
||||||
command: |
|
command: |
|
||||||
[[ $CI_PULL_REQUEST == "" ]] || { echo "Running on a PR - notification skipped."; exit 0; }
|
# FIXME: Checking $CIRCLE_PULL_REQUEST would be better than hard-coding branch names
|
||||||
|
# but it's broken. CircleCI associates runs on develop/breaking with random old PRs.
|
||||||
|
[[ $CIRCLE_BRANCH == develop || $CIRCLE_BRANCH == breaking ]] || { echo "Running on a PR or a feature branch - notification skipped."; exit 0; }
|
||||||
|
|
||||||
[[ "<< parameters.event >>" == "failure" ]] && message=" ❌ Nightly job **${CIRCLE_JOB}** failed on **${CIRCLE_BRANCH}**. Please see [build #${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details."
|
# Workflow name is not exposed as an env variable. Has to be queried from the API.
|
||||||
[[ "<< parameters.event >>" == "success" ]] && message=" ✅ Nightly job **${CIRCLE_JOB}** succeeded on **${CIRCLE_BRANCH}**. Please see [build #${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details."
|
# The name is not critical so if anything fails, use the raw workflow ID as a fallback.
|
||||||
|
workflow_info=$(curl --silent "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}") || true
|
||||||
|
workflow_name=$(echo "$workflow_info" | grep -E '"\s*name"\s*:\s*".*"' | cut -d \" -f 4 || echo "$CIRCLE_WORKFLOW_ID")
|
||||||
|
|
||||||
|
[[ "<< parameters.event >>" == "failure" ]] && message=" ❌ [${workflow_name}] Job **${CIRCLE_JOB}** failed on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details."
|
||||||
|
[[ "<< parameters.event >>" == "success" ]] && message=" ✅ [${workflow_name}] Job **${CIRCLE_JOB}** succeeded on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details."
|
||||||
|
|
||||||
curl "https://api.gitter.im/v1/rooms/${GITTER_NOTIFY_ROOM_ID}/chatMessages" \
|
curl "https://api.gitter.im/v1/rooms/${GITTER_NOTIFY_ROOM_ID}/chatMessages" \
|
||||||
--request POST \
|
--request POST \
|
||||||
@ -219,6 +226,14 @@ defaults:
|
|||||||
- image: << pipeline.parameters.ubuntu-1604-clang-ossfuzz-docker-image >>
|
- image: << pipeline.parameters.ubuntu-1604-clang-ossfuzz-docker-image >>
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 3
|
||||||
|
|
||||||
|
- base_ubuntu1604_clang_small: &base_ubuntu1604_clang_small
|
||||||
|
<<: *base_ubuntu1604_clang
|
||||||
|
resource_class: small
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
- base_ubuntu2004_clang: &base_ubuntu2004_clang
|
- base_ubuntu2004_clang: &base_ubuntu2004_clang
|
||||||
docker:
|
docker:
|
||||||
@ -229,20 +244,44 @@ defaults:
|
|||||||
CXX: clang++
|
CXX: clang++
|
||||||
MAKEFLAGS: -j 3
|
MAKEFLAGS: -j 3
|
||||||
|
|
||||||
- base_ubuntu2004_clang_xlarge: &base_ubuntu2004_clang_xlarge
|
- base_ubuntu2004_clang_small: &base_ubuntu2004_clang_small
|
||||||
<<: *base_ubuntu2004_clang
|
<<: *base_ubuntu2004_clang
|
||||||
resource_class: xlarge
|
resource_class: small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
CC: clang
|
CC: clang
|
||||||
CXX: clang++
|
CXX: clang++
|
||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
|
- base_ubuntu2004_clang_large: &base_ubuntu2004_clang_large
|
||||||
|
<<: *base_ubuntu2004_clang
|
||||||
|
resource_class: large
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
CC: clang
|
||||||
|
CXX: clang++
|
||||||
|
MAKEFLAGS: -j 5
|
||||||
|
|
||||||
- base_ubuntu2004: &base_ubuntu2004
|
- base_ubuntu2004: &base_ubuntu2004
|
||||||
docker:
|
docker:
|
||||||
- image: << pipeline.parameters.ubuntu-2004-docker-image >>
|
- image: << pipeline.parameters.ubuntu-2004-docker-image >>
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 3
|
||||||
|
|
||||||
|
- base_ubuntu2004_small: &base_ubuntu2004_small
|
||||||
|
<<: *base_ubuntu2004
|
||||||
|
resource_class: small
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
|
- base_ubuntu2004_large: &base_ubuntu2004_large
|
||||||
|
<<: *base_ubuntu2004
|
||||||
|
resource_class: large
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 5
|
||||||
|
|
||||||
- base_ubuntu2004_xlarge: &base_ubuntu2004_xlarge
|
- base_ubuntu2004_xlarge: &base_ubuntu2004_xlarge
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004
|
||||||
@ -251,29 +290,48 @@ defaults:
|
|||||||
TERM: xterm
|
TERM: xterm
|
||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 10
|
||||||
|
|
||||||
- base_buildpack_focal: &base_buildpack_focal
|
- base_buildpack_focal_small: &base_buildpack_focal_small
|
||||||
docker:
|
docker:
|
||||||
- image: buildpack-deps:focal
|
- image: buildpack-deps:focal
|
||||||
|
resource_class: small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
- base_buildpack_latest: &base_buildpack_latest
|
- base_buildpack_latest_small: &base_buildpack_latest_small
|
||||||
docker:
|
docker:
|
||||||
- image: buildpack-deps:latest
|
- image: buildpack-deps:latest
|
||||||
|
resource_class: small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
- base_archlinux: &base_archlinux
|
- base_archlinux: &base_archlinux
|
||||||
docker:
|
docker:
|
||||||
- image: archlinux:base
|
- image: archlinux:base
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 3
|
||||||
|
|
||||||
|
- base_archlinux_large: &base_archlinux_large
|
||||||
|
docker:
|
||||||
|
- image: archlinux:base
|
||||||
|
resource_class: large
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 5
|
||||||
|
|
||||||
- base_win_powershell: &base_win_powershell
|
- base_win_powershell: &base_win_powershell
|
||||||
executor:
|
executor:
|
||||||
name: win/default
|
name: win/default
|
||||||
shell: powershell.exe
|
shell: powershell.exe
|
||||||
|
|
||||||
|
- base_win_powershell_large: &base_win_powershell_large
|
||||||
|
executor:
|
||||||
|
name: win/default
|
||||||
|
shell: powershell.exe
|
||||||
|
size: large
|
||||||
|
|
||||||
- base_win_cmd: &base_win_cmd
|
- base_win_cmd: &base_win_cmd
|
||||||
executor:
|
executor:
|
||||||
name: win/default
|
name: win/default
|
||||||
@ -284,26 +342,31 @@ defaults:
|
|||||||
xcode: "11.0.0"
|
xcode: "11.0.0"
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 5
|
||||||
|
|
||||||
- base_ems_xlarge: &base_ems_xlarge
|
- base_ems_large: &base_ems_large
|
||||||
docker:
|
docker:
|
||||||
- image: << pipeline.parameters.emscripten-docker-image >>
|
- image: << pipeline.parameters.emscripten-docker-image >>
|
||||||
resource_class: xlarge
|
resource_class: large
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 5
|
||||||
|
|
||||||
- base_python: &base_python
|
- base_python_small: &base_python_small
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/python:3.6
|
- image: circleci/python:3.6
|
||||||
|
resource_class: small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
- base_node_latest: &base_node_latest
|
- base_node_latest_small: &base_node_latest_small
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node
|
- image: circleci/node
|
||||||
|
resource_class: small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 2
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# Workflow Templates
|
# Workflow Templates
|
||||||
@ -333,6 +396,11 @@ defaults:
|
|||||||
requires:
|
requires:
|
||||||
- b_ubu_release
|
- b_ubu_release
|
||||||
|
|
||||||
|
- workflow_ubuntu2004_static: &workflow_ubuntu2004_static
|
||||||
|
<<: *workflow_trigger_on_tags
|
||||||
|
requires:
|
||||||
|
- b_ubu_static
|
||||||
|
|
||||||
- workflow_archlinux: &workflow_archlinux
|
- workflow_archlinux: &workflow_archlinux
|
||||||
<<: *workflow_trigger_on_tags
|
<<: *workflow_trigger_on_tags
|
||||||
requires:
|
requires:
|
||||||
@ -387,7 +455,7 @@ defaults:
|
|||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
chk_spelling:
|
chk_spelling:
|
||||||
<<: *base_python
|
<<: *base_python_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
@ -402,7 +470,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_docs_examples:
|
chk_docs_examples:
|
||||||
<<: *base_node_latest
|
<<: *base_node_latest_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
@ -416,7 +484,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_coding_style:
|
chk_coding_style:
|
||||||
<<: *base_buildpack_focal
|
<<: *base_buildpack_focal_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -434,7 +502,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_errorcodes:
|
chk_errorcodes:
|
||||||
<<: *base_python
|
<<: *base_python_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -443,7 +511,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_pylint:
|
chk_pylint:
|
||||||
<<: *base_buildpack_focal
|
<<: *base_buildpack_focal_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -459,7 +527,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_antlr_grammar:
|
chk_antlr_grammar:
|
||||||
<<: *base_buildpack_focal
|
<<: *base_buildpack_focal_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -471,7 +539,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_buglist:
|
chk_buglist:
|
||||||
<<: *base_node_latest
|
<<: *base_node_latest_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -486,7 +554,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_proofs:
|
chk_proofs:
|
||||||
<<: *base_buildpack_latest
|
<<: *base_buildpack_latest_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -499,14 +567,14 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
chk_docs_pragma_min_version:
|
chk_docs_pragma_min_version:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: *run_docs_pragma_min_version
|
- run: *run_docs_pragma_min_version
|
||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
t_ubu_pyscripts:
|
t_ubu_pyscripts:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -525,6 +593,8 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_ubu: &b_ubu
|
b_ubu: &b_ubu
|
||||||
|
# this runs 2x faster on xlarge but takes 4x more resources (compared to medium).
|
||||||
|
# Enough other jobs depend on it that it's worth it though.
|
||||||
<<: *base_ubuntu2004_xlarge
|
<<: *base_ubuntu2004_xlarge
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
@ -537,10 +607,11 @@ jobs:
|
|||||||
|
|
||||||
# x64 ASAN build, for testing for memory related bugs
|
# x64 ASAN build, for testing for memory related bugs
|
||||||
b_ubu_asan: &b_ubu_asan
|
b_ubu_asan: &b_ubu_asan
|
||||||
<<: *base_ubuntu2004_xlarge
|
# Runs slightly faster on large and xlarge but we only run it nightly so efficiency matters more.
|
||||||
|
<<: *base_ubuntu2004
|
||||||
environment:
|
environment:
|
||||||
CMAKE_OPTIONS: -DSANITIZE=address
|
CMAKE_OPTIONS: -DSANITIZE=address
|
||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 3
|
||||||
CMAKE_BUILD_TYPE: Release
|
CMAKE_BUILD_TYPE: Release
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
@ -550,7 +621,12 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_ubu_clang: &b_ubu_clang
|
b_ubu_clang: &b_ubu_clang
|
||||||
<<: *base_ubuntu2004_clang_xlarge
|
<<: *base_ubuntu2004_clang_large
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
CC: clang
|
||||||
|
CXX: clang++
|
||||||
|
MAKEFLAGS: -j 10
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: *run_build
|
- run: *run_build
|
||||||
@ -559,6 +635,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_ubu_asan_clang: &b_ubu_asan_clang
|
b_ubu_asan_clang: &b_ubu_asan_clang
|
||||||
|
# This runs a bit faster on large and xlarge but on nightly efficiency matters more.
|
||||||
<<: *base_ubuntu2004_clang
|
<<: *base_ubuntu2004_clang
|
||||||
environment:
|
environment:
|
||||||
CC: clang
|
CC: clang
|
||||||
@ -573,6 +650,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_ubu_ubsan_clang: &b_ubu_ubsan_clang
|
b_ubu_ubsan_clang: &b_ubu_ubsan_clang
|
||||||
|
# This runs a bit faster on large and xlarge but on nightly efficiency matters more.
|
||||||
<<: *base_ubuntu2004_clang
|
<<: *base_ubuntu2004_clang
|
||||||
environment:
|
environment:
|
||||||
CC: clang
|
CC: clang
|
||||||
@ -593,8 +671,10 @@ jobs:
|
|||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 10
|
||||||
|
|
||||||
b_ubu_static:
|
b_ubu_static:
|
||||||
|
# On large runs 2x faster than on medium. 3x on xlarge.
|
||||||
<<: *base_ubuntu2004_xlarge
|
<<: *base_ubuntu2004_xlarge
|
||||||
environment:
|
environment:
|
||||||
|
TERM: xterm
|
||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 10
|
||||||
CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release -DUSE_Z3_DLOPEN=ON -DUSE_CVC4=OFF -DSOLC_STATIC_STDLIBS=ON
|
CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release -DUSE_Z3_DLOPEN=ON -DUSE_CVC4=OFF -DSOLC_STATIC_STDLIBS=ON
|
||||||
steps:
|
steps:
|
||||||
@ -604,14 +684,16 @@ jobs:
|
|||||||
name: strip binary
|
name: strip binary
|
||||||
command: strip build/solc/solc
|
command: strip build/solc/solc
|
||||||
- store_artifacts: *artifacts_solc
|
- store_artifacts: *artifacts_solc
|
||||||
|
- persist_to_workspace: *artifacts_executables
|
||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_ubu_codecov:
|
b_ubu_codecov:
|
||||||
<<: *base_ubuntu2004_xlarge
|
# Runs ~30% faster on large but we only run it nightly so efficiency matters more.
|
||||||
|
<<: *base_ubuntu2004
|
||||||
environment:
|
environment:
|
||||||
COVERAGE: ON
|
COVERAGE: ON
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Debug
|
||||||
MAKEFLAGS: -j 10
|
MAKEFLAGS: -j 3
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: *run_build
|
- run: *run_build
|
||||||
@ -620,7 +702,6 @@ jobs:
|
|||||||
|
|
||||||
t_ubu_codecov:
|
t_ubu_codecov:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004
|
||||||
parallelism: 6
|
|
||||||
environment:
|
environment:
|
||||||
EVM: << pipeline.parameters.evm-version >>
|
EVM: << pipeline.parameters.evm-version >>
|
||||||
OPTIMIZE: 1
|
OPTIMIZE: 1
|
||||||
@ -644,7 +725,7 @@ jobs:
|
|||||||
# Builds in C++20 mode and uses debug build in order to speed up.
|
# Builds in C++20 mode and uses debug build in order to speed up.
|
||||||
# Do *NOT* store any artifacts or workspace as we don't run tests on this build.
|
# Do *NOT* store any artifacts or workspace as we don't run tests on this build.
|
||||||
b_ubu_cxx20:
|
b_ubu_cxx20:
|
||||||
<<: *base_ubuntu2004_xlarge
|
<<: *base_ubuntu2004_large
|
||||||
environment:
|
environment:
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Debug
|
||||||
CMAKE_OPTIONS: -DCMAKE_CXX_STANDARD=20 -DUSE_CVC4=OFF
|
CMAKE_OPTIONS: -DCMAKE_CXX_STANDARD=20 -DUSE_CVC4=OFF
|
||||||
@ -664,7 +745,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
t_ubu_ossfuzz: &t_ubu_ossfuzz
|
t_ubu_ossfuzz: &t_ubu_ossfuzz
|
||||||
<<: *base_ubuntu1604_clang
|
<<: *base_ubuntu1604_clang_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
@ -681,10 +762,10 @@ jobs:
|
|||||||
- gitter_notify_success_unless_pr
|
- gitter_notify_success_unless_pr
|
||||||
|
|
||||||
b_archlinux:
|
b_archlinux:
|
||||||
<<: *base_archlinux
|
<<: *base_archlinux_large
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
MAKEFLAGS: -j 3
|
MAKEFLAGS: -j 5
|
||||||
steps:
|
steps:
|
||||||
- run:
|
- run:
|
||||||
name: Install build dependencies
|
name: Install build dependencies
|
||||||
@ -765,7 +846,10 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_ems:
|
b_ems:
|
||||||
<<: *base_ems_xlarge
|
<<: *base_ems_large
|
||||||
|
environment:
|
||||||
|
TERM: xterm
|
||||||
|
MAKEFLAGS: -j 10
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@ -786,7 +870,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_docs:
|
b_docs:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: *setup_prerelease_commit_hash
|
- run: *setup_prerelease_commit_hash
|
||||||
@ -800,7 +884,7 @@ jobs:
|
|||||||
|
|
||||||
t_ubu_soltest_all: &t_ubu_soltest_all
|
t_ubu_soltest_all: &t_ubu_soltest_all
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004
|
||||||
parallelism: 6
|
parallelism: 15 # 7 EVM versions, each with/without optimization + 1 ABIv1/@nooptions run
|
||||||
<<: *steps_soltest_all
|
<<: *steps_soltest_all
|
||||||
|
|
||||||
t_archlinux_soltest: &t_archlinux_soltest
|
t_archlinux_soltest: &t_archlinux_soltest
|
||||||
@ -843,14 +927,15 @@ jobs:
|
|||||||
<<: *t_ubu_soltest_all
|
<<: *t_ubu_soltest_all
|
||||||
|
|
||||||
t_ubu_cli: &t_ubu_cli
|
t_ubu_cli: &t_ubu_cli
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004_small
|
||||||
<<: *steps_cmdline_tests
|
<<: *steps_cmdline_tests
|
||||||
|
|
||||||
t_ubu_release_cli: &t_ubu_release_cli
|
t_ubu_release_cli: &t_ubu_release_cli
|
||||||
<<: *t_ubu_cli
|
<<: *t_ubu_cli
|
||||||
|
|
||||||
t_ubu_asan_cli:
|
t_ubu_asan_cli:
|
||||||
<<: *base_ubuntu2004
|
# Runs slightly faster on medium but we only run it nightly so efficiency matters more.
|
||||||
|
<<: *base_ubuntu2004_small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2
|
ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2
|
||||||
@ -858,7 +943,6 @@ jobs:
|
|||||||
|
|
||||||
t_ubu_asan_soltest:
|
t_ubu_asan_soltest:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004
|
||||||
parallelism: 6
|
|
||||||
environment:
|
environment:
|
||||||
EVM: << pipeline.parameters.evm-version >>
|
EVM: << pipeline.parameters.evm-version >>
|
||||||
OPTIMIZE: 0
|
OPTIMIZE: 0
|
||||||
@ -882,10 +966,11 @@ jobs:
|
|||||||
<<: *steps_soltest
|
<<: *steps_soltest
|
||||||
|
|
||||||
t_ubu_ubsan_clang_cli:
|
t_ubu_ubsan_clang_cli:
|
||||||
<<: *base_ubuntu2004_clang
|
<<: *base_ubuntu2004_clang_small
|
||||||
<<: *steps_cmdline_tests
|
<<: *steps_cmdline_tests
|
||||||
|
|
||||||
t_ems_solcjs:
|
t_ems_solcjs:
|
||||||
|
# Unlike other t_ems jobs this one actually runs 2x faster on medium (compared to small).
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
@ -906,7 +991,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
t_ems_ext_hardhat:
|
t_ems_ext_hardhat:
|
||||||
<<: *base_node_latest
|
<<: *base_node_latest_small
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
HARDHAT_TESTS_SOLC_PATH: /tmp/workspace/soljson.js
|
HARDHAT_TESTS_SOLC_PATH: /tmp/workspace/soljson.js
|
||||||
@ -935,14 +1020,25 @@ jobs:
|
|||||||
parameters:
|
parameters:
|
||||||
project:
|
project:
|
||||||
type: string
|
type: string
|
||||||
|
binary_type:
|
||||||
|
type: enum
|
||||||
|
enum:
|
||||||
|
- solcjs
|
||||||
|
- native
|
||||||
compile_only:
|
compile_only:
|
||||||
type: integer
|
type: integer
|
||||||
default: 0
|
default: 0
|
||||||
nodejs_version:
|
nodejs_version:
|
||||||
type: integer
|
type: string
|
||||||
default: 14
|
default: latest
|
||||||
|
resource_class:
|
||||||
|
type: string
|
||||||
|
default: small
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/node:<<parameters.nodejs_version>>
|
- image: circleci/node:<<parameters.nodejs_version>>
|
||||||
|
resource_class: <<parameters.resource_class>>
|
||||||
|
# NOTE: Each external test does 3 separate compile&test runs
|
||||||
|
parallelism: 3
|
||||||
environment:
|
environment:
|
||||||
TERM: xterm
|
TERM: xterm
|
||||||
COMPILE_ONLY: <<parameters.compile_only>>
|
COMPILE_ONLY: <<parameters.compile_only>>
|
||||||
@ -951,18 +1047,30 @@ jobs:
|
|||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- run:
|
- run:
|
||||||
name: Install dependencies
|
name: Install lsof
|
||||||
command: |
|
command: |
|
||||||
# lsof is used by Colony in its stop-blockchain-client.sh script
|
# lsof is used by Colony in its stop-blockchain-client.sh script
|
||||||
sudo apt-get -qy install lsof
|
sudo apt-get --quiet --assume-yes --no-install-recommends install lsof
|
||||||
|
- when:
|
||||||
|
condition:
|
||||||
|
equal: [<< parameters.binary_type >>, "solcjs"]
|
||||||
|
steps:
|
||||||
- run:
|
- run:
|
||||||
name: External <<parameters.project>> tests
|
name: External <<parameters.project>> tests (solcjs)
|
||||||
command: |
|
command: |
|
||||||
test/externalTests/<<parameters.project>>.sh /tmp/workspace/soljson.js
|
test/externalTests/<<parameters.project>>.sh solcjs /tmp/workspace/soljson.js
|
||||||
|
- when:
|
||||||
|
condition:
|
||||||
|
equal: [<< parameters.binary_type >>, "native"]
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: External <<parameters.project>> tests (native)
|
||||||
|
command: |
|
||||||
|
test/externalTests/<<parameters.project>>.sh native /tmp/workspace/solc/solc
|
||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_win: &b_win
|
b_win: &b_win
|
||||||
<<: *base_win_powershell
|
<<: *base_win_powershell_large
|
||||||
steps:
|
steps:
|
||||||
# NOTE: Not disabling git's core.autocrlf here because we want to build using the typical Windows config.
|
# NOTE: Not disabling git's core.autocrlf here because we want to build using the typical Windows config.
|
||||||
- checkout
|
- checkout
|
||||||
@ -1019,7 +1127,7 @@ jobs:
|
|||||||
<<: *t_win_soltest
|
<<: *t_win_soltest
|
||||||
|
|
||||||
b_bytecode_ubu:
|
b_bytecode_ubu:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004_small
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
@ -1085,7 +1193,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
b_bytecode_ems:
|
b_bytecode_ems:
|
||||||
<<: *base_node_latest
|
<<: *base_node_latest_small
|
||||||
environment:
|
environment:
|
||||||
SOLC_EMSCRIPTEN: "On"
|
SOLC_EMSCRIPTEN: "On"
|
||||||
steps:
|
steps:
|
||||||
@ -1102,7 +1210,7 @@ jobs:
|
|||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
|
|
||||||
t_bytecode_compare:
|
t_bytecode_compare:
|
||||||
<<: *base_ubuntu2004
|
<<: *base_ubuntu2004_small
|
||||||
environment:
|
environment:
|
||||||
REPORT_FILES: |
|
REPORT_FILES: |
|
||||||
bytecode-report-emscripten.txt
|
bytecode-report-emscripten.txt
|
||||||
@ -1191,58 +1299,53 @@ workflows:
|
|||||||
- t_ems_solcjs: *workflow_emscripten
|
- t_ems_solcjs: *workflow_emscripten
|
||||||
- t_ems_ext_hardhat: *workflow_emscripten
|
- t_ems_ext_hardhat: *workflow_emscripten
|
||||||
|
|
||||||
|
# Separate compile-only runs of those external tests where a full run takes much longer.
|
||||||
- t_ems_ext:
|
- t_ems_ext:
|
||||||
<<: *workflow_emscripten
|
<<: *workflow_emscripten
|
||||||
name: t_ems_compile_ext_colony
|
name: t_ems_compile_ext_colony
|
||||||
project: colony
|
project: colony
|
||||||
|
binary_type: solcjs
|
||||||
compile_only: 1
|
compile_only: 1
|
||||||
|
nodejs_version: '14'
|
||||||
- t_ems_ext:
|
- t_ems_ext:
|
||||||
<<: *workflow_emscripten
|
<<: *workflow_ubuntu2004_static
|
||||||
name: t_ems_compile_ext_gnosis
|
name: t_native_compile_ext_gnosis
|
||||||
project: gnosis
|
project: gnosis
|
||||||
|
binary_type: native
|
||||||
compile_only: 1
|
compile_only: 1
|
||||||
- t_ems_ext:
|
nodejs_version: '14'
|
||||||
<<: *workflow_emscripten
|
|
||||||
name: t_ems_compile_ext_gnosis_v2
|
|
||||||
project: gnosis-v2
|
|
||||||
compile_only: 1
|
|
||||||
- t_ems_ext:
|
|
||||||
<<: *workflow_emscripten
|
|
||||||
name: t_ems_compile_ext_zeppelin
|
|
||||||
project: zeppelin
|
|
||||||
compile_only: 1
|
|
||||||
- t_ems_ext:
|
|
||||||
<<: *workflow_emscripten
|
|
||||||
name: t_ems_compile_ext_ens
|
|
||||||
project: ens
|
|
||||||
compile_only: 1
|
|
||||||
# NOTE: One of the dependencies (fsevents) fails to build its native extension on node.js 12+.
|
|
||||||
nodejs_version: 10
|
|
||||||
|
|
||||||
# FIXME: Gnosis tests are pretty flaky right now. They often fail on CircleCI due to random ProviderError
|
# FIXME: Gnosis tests are pretty flaky right now. They often fail on CircleCI due to random ProviderError
|
||||||
# and there are also other less frequent problems. See https://github.com/gnosis/safe-contracts/issues/216.
|
# and there are also other less frequent problems. See https://github.com/gnosis/safe-contracts/issues/216.
|
||||||
#- t_ems_ext:
|
#- t_ems_ext:
|
||||||
# <<: *workflow_emscripten
|
# <<: *workflow_emscripten
|
||||||
# name: t_ems_test_ext_gnosis
|
# name: t_native_test_ext_gnosis
|
||||||
# project: gnosis
|
# project: gnosis
|
||||||
|
# binary_type: native
|
||||||
# # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1").
|
# # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1").
|
||||||
# nodejs_version: 12
|
# nodejs_version: '12'
|
||||||
- t_ems_ext:
|
- t_ems_ext:
|
||||||
<<: *workflow_emscripten
|
<<: *workflow_ubuntu2004_static
|
||||||
name: t_ems_test_ext_gnosis_v2
|
name: t_native_test_ext_gnosis_v2
|
||||||
project: gnosis-v2
|
project: gnosis-v2
|
||||||
|
binary_type: native
|
||||||
# NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1").
|
# NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1").
|
||||||
nodejs_version: 12
|
nodejs_version: '12'
|
||||||
- t_ems_ext:
|
- t_ems_ext:
|
||||||
<<: *workflow_emscripten
|
<<: *workflow_ubuntu2004_static
|
||||||
name: t_ems_test_ext_zeppelin
|
name: t_native_test_ext_zeppelin
|
||||||
project: zeppelin
|
project: zeppelin
|
||||||
|
binary_type: native
|
||||||
|
# NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported"
|
||||||
|
nodejs_version: '16'
|
||||||
|
resource_class: large
|
||||||
- t_ems_ext:
|
- t_ems_ext:
|
||||||
<<: *workflow_emscripten
|
<<: *workflow_ubuntu2004_static
|
||||||
name: t_ems_test_ext_ens
|
name: t_native_test_ext_ens
|
||||||
project: ens
|
project: ens
|
||||||
|
binary_type: native
|
||||||
# NOTE: One of the dependencies (fsevents) fails to build its native extension on node.js 12+.
|
# NOTE: One of the dependencies (fsevents) fails to build its native extension on node.js 12+.
|
||||||
nodejs_version: 10
|
nodejs_version: '10'
|
||||||
|
|
||||||
# Windows build and tests
|
# Windows build and tests
|
||||||
- b_win: *workflow_trigger_on_tags
|
- b_win: *workflow_trigger_on_tags
|
||||||
@ -1307,3 +1410,6 @@ workflows:
|
|||||||
<<: *workflow_emscripten
|
<<: *workflow_emscripten
|
||||||
name: t_ems_test_ext_colony
|
name: t_ems_test_ext_colony
|
||||||
project: colony
|
project: colony
|
||||||
|
binary_type: solcjs
|
||||||
|
nodejs_version: '14'
|
||||||
|
resource_class: medium
|
||||||
|
@ -57,14 +57,15 @@ then
|
|||||||
brew install cmake
|
brew install cmake
|
||||||
brew install wget
|
brew install wget
|
||||||
brew install coreutils
|
brew install coreutils
|
||||||
|
brew install diffutils
|
||||||
./scripts/install_obsolete_jsoncpp_1_7_4.sh
|
./scripts/install_obsolete_jsoncpp_1_7_4.sh
|
||||||
|
|
||||||
# z3
|
# z3
|
||||||
z3_version="4.8.12"
|
z3_version="4.8.13"
|
||||||
z3_dir="z3-${z3_version}-x64-osx-10.15.7"
|
z3_dir="z3-${z3_version}-x64-osx-10.16"
|
||||||
z3_package="${z3_dir}.zip"
|
z3_package="${z3_dir}.zip"
|
||||||
wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}"
|
wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}"
|
||||||
validate_checksum "$z3_package" a1f6ef3c99456147c4d3f2652dc6bc90951c4ab3fe7741a255eb794f0ab8938c
|
validate_checksum "$z3_package" 191b26be2b617b2dffffce139d77abcd7e584859efbc10a58d01a1d7830697a4
|
||||||
unzip "$z3_package"
|
unzip "$z3_package"
|
||||||
rm "$z3_package"
|
rm "$z3_package"
|
||||||
cp "${z3_dir}/bin/libz3.a" /usr/local/lib
|
cp "${z3_dir}/bin/libz3.a" /usr/local/lib
|
||||||
|
@ -28,27 +28,32 @@ set -e
|
|||||||
|
|
||||||
REPODIR="$(realpath "$(dirname "$0")"/..)"
|
REPODIR="$(realpath "$(dirname "$0")"/..)"
|
||||||
|
|
||||||
|
# shellcheck source=scripts/common.sh
|
||||||
|
source "${REPODIR}/scripts/common.sh"
|
||||||
|
|
||||||
|
# NOTE: If you add/remove values, remember to update `parallelism` setting in CircleCI config.
|
||||||
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london)
|
EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london)
|
||||||
DEFAULT_EVM=london
|
DEFAULT_EVM=london
|
||||||
[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
|
[[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]]
|
||||||
OPTIMIZE_VALUES=(0 1)
|
OPTIMIZE_VALUES=(0 1)
|
||||||
STEPS=$(( 1 + ${#EVM_VALUES[@]} * ${#OPTIMIZE_VALUES[@]} ))
|
STEPS=$(( 1 + ${#EVM_VALUES[@]} * ${#OPTIMIZE_VALUES[@]} ))
|
||||||
|
|
||||||
if (( CIRCLE_NODE_TOTAL )) && (( CIRCLE_NODE_TOTAL > 1 ))
|
RUN_STEPS=$(circleci_select_steps "$(seq "$STEPS")")
|
||||||
then
|
printTask "Running steps $RUN_STEPS..."
|
||||||
RUN_STEPS=$(seq "$STEPS" | circleci tests split | xargs)
|
|
||||||
else
|
|
||||||
RUN_STEPS=$(seq "$STEPS" | xargs)
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Running steps $RUN_STEPS..."
|
|
||||||
|
|
||||||
STEP=1
|
STEP=1
|
||||||
|
|
||||||
|
|
||||||
# Run for ABI encoder v1, without SMTChecker tests.
|
# Run for ABI encoder v1, without SMTChecker tests.
|
||||||
[[ " $RUN_STEPS " == *" $STEP "* ]] && EVM="${DEFAULT_EVM}" OPTIMIZE=1 ABI_ENCODER_V1=1 BOOST_TEST_ARGS="-t !smtCheckerTests" "${REPODIR}/.circleci/soltest.sh"
|
if circleci_step_selected "$RUN_STEPS" "$STEP"
|
||||||
STEP=$((STEP + 1))
|
then
|
||||||
|
EVM="${DEFAULT_EVM}" \
|
||||||
|
OPTIMIZE=1 \
|
||||||
|
ABI_ENCODER_V1=1 \
|
||||||
|
BOOST_TEST_ARGS="-t !smtCheckerTests" \
|
||||||
|
"${REPODIR}/.circleci/soltest.sh"
|
||||||
|
fi
|
||||||
|
((++STEP))
|
||||||
|
|
||||||
for OPTIMIZE in "${OPTIMIZE_VALUES[@]}"
|
for OPTIMIZE in "${OPTIMIZE_VALUES[@]}"
|
||||||
do
|
do
|
||||||
@ -63,13 +68,16 @@ do
|
|||||||
DISABLE_SMTCHECKER=""
|
DISABLE_SMTCHECKER=""
|
||||||
[ "${OPTIMIZE}" != "0" ] && DISABLE_SMTCHECKER="-t !smtCheckerTests"
|
[ "${OPTIMIZE}" != "0" ] && DISABLE_SMTCHECKER="-t !smtCheckerTests"
|
||||||
|
|
||||||
[[ " $RUN_STEPS " == *" $STEP "* ]] && EVM="$EVM" OPTIMIZE="$OPTIMIZE" SOLTEST_FLAGS="$SOLTEST_FLAGS $ENFORCE_GAS_ARGS $EWASM_ARGS" BOOST_TEST_ARGS="-t !@nooptions $DISABLE_SMTCHECKER" "${REPODIR}/.circleci/soltest.sh"
|
if circleci_step_selected "$RUN_STEPS" "$STEP"
|
||||||
STEP=$((STEP + 1))
|
then
|
||||||
|
EVM="$EVM" \
|
||||||
|
OPTIMIZE="$OPTIMIZE" \
|
||||||
|
SOLTEST_FLAGS="$SOLTEST_FLAGS $ENFORCE_GAS_ARGS $EWASM_ARGS" \
|
||||||
|
BOOST_TEST_ARGS="-t !@nooptions $DISABLE_SMTCHECKER" \
|
||||||
|
"${REPODIR}/.circleci/soltest.sh"
|
||||||
|
fi
|
||||||
|
((++STEP))
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
if ((STEP != STEPS + 1))
|
((STEP == STEPS + 1)) || assertFail "Step counter not properly adjusted!"
|
||||||
then
|
|
||||||
echo "Step counter not properly adjusted!" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
@ -65,7 +65,7 @@ configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" include/licens
|
|||||||
|
|
||||||
include(EthOptions)
|
include(EthOptions)
|
||||||
configure_project(TESTS)
|
configure_project(TESTS)
|
||||||
set(LATEST_Z3_VERSION "4.8.12")
|
set(LATEST_Z3_VERSION "4.8.13")
|
||||||
set(MINIMUM_Z3_VERSION "4.8.0")
|
set(MINIMUM_Z3_VERSION "4.8.0")
|
||||||
find_package(Z3)
|
find_package(Z3)
|
||||||
if (${Z3_FOUND})
|
if (${Z3_FOUND})
|
||||||
|
@ -16,6 +16,10 @@ Compiler Features:
|
|||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
* Code Generator: Fix a crash when using ``@use-src`` and compiling from Yul to ewasm.
|
||||||
|
* SMTChecker: Fix internal error when an unsafe target is solved more than once and the counterexample messages are different.
|
||||||
|
* Fix internal error when a function has a calldata struct argument with an internal type inside.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 0.8.10 (2021-11-09)
|
### 0.8.10 (2021-11-09)
|
||||||
@ -111,7 +115,7 @@ Bugfixes:
|
|||||||
* SMTChecker: Fix false positive in external calls from constructors.
|
* SMTChecker: Fix false positive in external calls from constructors.
|
||||||
* SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants.
|
* SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants.
|
||||||
* Standard JSON: Fix non-fatal errors in Yul mode being discarded if followed by a fatal error.
|
* Standard JSON: Fix non-fatal errors in Yul mode being discarded if followed by a fatal error.
|
||||||
* Type Checker: Correct wrong error message in inline assembly complaining about ``.slot`` or ``.offset` not valid when actually ``.length`` was used.
|
* Type Checker: Correct wrong error message in inline assembly complaining about ``.slot`` or ``.offset`` not valid when actually ``.length`` was used.
|
||||||
* Type Checker: Disallow modifier declarations and definitions in interfaces.
|
* Type Checker: Disallow modifier declarations and definitions in interfaces.
|
||||||
* Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments.
|
* Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments.
|
||||||
|
|
||||||
|
8
docs/_templates/versions.html
vendored
8
docs/_templates/versions.html
vendored
@ -13,13 +13,13 @@
|
|||||||
</span>
|
</span>
|
||||||
<div class="rst-other-versions">
|
<div class="rst-other-versions">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>{{ _('Versions') }}</dt> {% for slug, url in versions %}
|
<dt>{{ _('Downloads') }}</dt> {% for type, url in downloads %}
|
||||||
<dd><a href="{{ url }}">{{ slug }}</a></dd>
|
<dd><a href="{{ url }}">{{ type }}</a></dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>{{ _('Downloads') }}</dt> {% for type, url in downloads %}
|
<dt>{{ _('Versions') }}</dt> {% for slug, url in versions %}
|
||||||
<dd><a href="{{ url }}">{{ type }}</a></dd>
|
<dd><a href="{{ url }}">{{ slug }}</a></dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
|
@ -749,7 +749,7 @@ Non-standard Packed Mode
|
|||||||
|
|
||||||
Through ``abi.encodePacked()``, Solidity supports a non-standard packed mode where:
|
Through ``abi.encodePacked()``, Solidity supports a non-standard packed mode where:
|
||||||
|
|
||||||
- types shorter than 32 bytes are neither zero padded nor sign extended and
|
- types shorter than 32 bytes are concatenated directly, without padding or sign extension
|
||||||
- dynamic types are encoded in-place and without the length.
|
- dynamic types are encoded in-place and without the length.
|
||||||
- array elements are padded, but still encoded in-place
|
- array elements are padded, but still encoded in-place
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ Under the following terms:
|
|||||||
|
|
||||||
- **Attribution** — You must give appropriate credit, provide a link to
|
- **Attribution** — You must give appropriate credit, provide a link to
|
||||||
the license, and indicate if changes were made. You may do so in any
|
the license, and indicate if changes were made. You may do so in any
|
||||||
reasonable manner, but not in any way that suggests the the Solidity
|
reasonable manner, but not in any way that suggests that the Solidity
|
||||||
core team endorses you or your use.
|
core team endorses you or your use.
|
||||||
|
|
||||||
When using the Solidity logo, please respect the Solidity logo guidelines.
|
When using the Solidity logo, please respect the Solidity logo guidelines.
|
||||||
|
@ -81,7 +81,7 @@ Global Variables
|
|||||||
- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: :ref:`ABI <ABI>`-encodes
|
- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: :ref:`ABI <ABI>`-encodes
|
||||||
the given arguments starting from the second and prepends the given four-byte selector
|
the given arguments starting from the second and prepends the given four-byte selector
|
||||||
- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent
|
- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent
|
||||||
to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)```
|
to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)``
|
||||||
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of
|
- ``bytes.concat(...) returns (bytes memory)``: :ref:`Concatenates variable number of
|
||||||
arguments to one byte array<bytes-concat>`
|
arguments to one byte array<bytes-concat>`
|
||||||
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_)
|
- ``block.basefee`` (``uint``): current block's base fee (`EIP-3198 <https://eips.ethereum.org/EIPS/eip-3198>`_ and `EIP-1559 <https://eips.ethereum.org/EIPS/eip-1559>`_)
|
||||||
|
@ -31,6 +31,12 @@ a 0.y.z version number `to indicate this fast pace of change <https://semver.org
|
|||||||
Ideas for improving Solidity or this documentation are always welcome,
|
Ideas for improving Solidity or this documentation are always welcome,
|
||||||
read our :doc:`contributors guide <contributing>` for more details.
|
read our :doc:`contributors guide <contributing>` for more details.
|
||||||
|
|
||||||
|
.. Hint::
|
||||||
|
|
||||||
|
You can download this documentation as PDF, HTML or Epub by clicking on the versions
|
||||||
|
flyout menu in the bottom-left corner and selecting the preferred download format.
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -521,7 +521,7 @@ ExpressionSplitter
|
|||||||
|
|
||||||
The expression splitter turns expressions like ``add(mload(0x123), mul(mload(0x456), 0x20))``
|
The expression splitter turns expressions like ``add(mload(0x123), mul(mload(0x456), 0x20))``
|
||||||
into a sequence of declarations of unique variables that are assigned sub-expressions
|
into a sequence of declarations of unique variables that are assigned sub-expressions
|
||||||
of that expression so that each function call has only variables or literals
|
of that expression so that each function call has only variables
|
||||||
as arguments.
|
as arguments.
|
||||||
|
|
||||||
The above would be transformed into
|
The above would be transformed into
|
||||||
@ -529,10 +529,13 @@ The above would be transformed into
|
|||||||
.. code-block:: yul
|
.. code-block:: yul
|
||||||
|
|
||||||
{
|
{
|
||||||
let _1 := mload(0x123)
|
let _1 := 0x20
|
||||||
let _2 := mul(_1, 0x20)
|
let _2 := 0x456
|
||||||
let _3 := mload(0x456)
|
let _3 := mload(_2)
|
||||||
let z := add(_3, _2)
|
let _4 := mul(_3, _1)
|
||||||
|
let _5 := 0x123
|
||||||
|
let _6 := mload(_5)
|
||||||
|
let z := add(_6, _4)
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that this transformation does not change the order of opcodes or function calls.
|
Note that this transformation does not change the order of opcodes or function calls.
|
||||||
@ -543,7 +546,7 @@ this "outlining" of the inner expressions in all cases. We can sidestep this lim
|
|||||||
|
|
||||||
The final program should be in a form such that (with the exception of loop conditions)
|
The final program should be in a form such that (with the exception of loop conditions)
|
||||||
function calls cannot appear nested inside expressions
|
function calls cannot appear nested inside expressions
|
||||||
and all function call arguments have to be literals or variables.
|
and all function call arguments have to be variables.
|
||||||
|
|
||||||
The benefits of this form are that it is much easier to re-order the sequence of opcodes
|
The benefits of this form are that it is much easier to re-order the sequence of opcodes
|
||||||
and it is also easier to perform function call inlining. Furthermore, it is simpler
|
and it is also easier to perform function call inlining. Furthermore, it is simpler
|
||||||
@ -972,10 +975,13 @@ BlockFlattener
|
|||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This stage eliminates nested blocks by inserting the statement in the
|
This stage eliminates nested blocks by inserting the statement in the
|
||||||
inner block at the appropriate place in the outer block:
|
inner block at the appropriate place in the outer block. It depends on the
|
||||||
|
FunctionGrouper and does not flatten the outermost block to keep the form
|
||||||
|
produced by the FunctionGrouper.
|
||||||
|
|
||||||
.. code-block:: yul
|
.. code-block:: yul
|
||||||
|
|
||||||
|
{
|
||||||
{
|
{
|
||||||
let x := 2
|
let x := 2
|
||||||
{
|
{
|
||||||
@ -983,16 +989,19 @@ inner block at the appropriate place in the outer block:
|
|||||||
mstore(x, y)
|
mstore(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
is transformed to
|
is transformed to
|
||||||
|
|
||||||
.. code-block:: yul
|
.. code-block:: yul
|
||||||
|
|
||||||
|
{
|
||||||
{
|
{
|
||||||
let x := 2
|
let x := 2
|
||||||
let y := 3
|
let y := 3
|
||||||
mstore(x, y)
|
mstore(x, y)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
As long as the code is disambiguated, this does not cause a problem because
|
As long as the code is disambiguated, this does not cause a problem because
|
||||||
the scopes of variables can only grow.
|
the scopes of variables can only grow.
|
||||||
|
@ -313,7 +313,7 @@ likely it will be.
|
|||||||
since it is not up to the submitter of a transaction, but up to the miners to determine in which block the transaction is included.
|
since it is not up to the submitter of a transaction, but up to the miners to determine in which block the transaction is included.
|
||||||
|
|
||||||
If you want to schedule future calls of your contract, you can use
|
If you want to schedule future calls of your contract, you can use
|
||||||
the `alarm clock <https://www.ethereum-alarm-clock.com/>`_ or a similar oracle service.
|
a smart contract automation tool or an oracle service.
|
||||||
|
|
||||||
.. _the-ethereum-virtual-machine:
|
.. _the-ethereum-virtual-machine:
|
||||||
|
|
||||||
@ -584,5 +584,5 @@ but instead is implemented in the EVM execution environment itself.
|
|||||||
Different EVM-compatible chains might use a different set of
|
Different EVM-compatible chains might use a different set of
|
||||||
precompiled contracts. It might also be possible that new
|
precompiled contracts. It might also be possible that new
|
||||||
precompiled contracts are added to the Ethereum main chain in the future,
|
precompiled contracts are added to the Ethereum main chain in the future,
|
||||||
but you can reasonabyly expect them to always be in the range between
|
but you can reasonably expect them to always be in the range between
|
||||||
``1`` and ``0xffff`` (inclusive).
|
``1`` and ``0xffff`` (inclusive).
|
@ -747,7 +747,7 @@ Yes:
|
|||||||
function thisFunctionNameIsReallyLong(
|
function thisFunctionNameIsReallyLong(
|
||||||
address x,
|
address x,
|
||||||
address y,
|
address y,
|
||||||
address z,
|
address z
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
onlyOwner
|
onlyOwner
|
||||||
|
@ -437,14 +437,16 @@ an error. You can prepend (for integer types) or append (for bytesNN types) zero
|
|||||||
Rational and Integer Literals
|
Rational and Integer Literals
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
Integer literals are formed from a sequence of numbers in the range 0-9.
|
Integer literals are formed from a sequence of digits in the range 0-9.
|
||||||
They are interpreted as decimals. For example, ``69`` means sixty nine.
|
They are interpreted as decimals. For example, ``69`` means sixty nine.
|
||||||
Octal literals do not exist in Solidity and leading zeros are invalid.
|
Octal literals do not exist in Solidity and leading zeros are invalid.
|
||||||
|
|
||||||
Decimal fraction literals are formed by a ``.`` with at least one number on
|
Decimal fractional literals are formed by a ``.`` with at least one number on
|
||||||
one side. Examples include ``1.``, ``.1`` and ``1.3``.
|
one side. Examples include ``1.``, ``.1`` and ``1.3``.
|
||||||
|
|
||||||
Scientific notation is also supported, where the base can have fractions and the exponent cannot.
|
Scientific notation in the form of ``2e10`` is also supported, where the
|
||||||
|
mantissa can be fractional but the exponent has to be an integer.
|
||||||
|
The literal ``MeE`` is equivalent to ``M * 10**E``.
|
||||||
Examples include ``2e10``, ``-2e10``, ``2e-10``, ``2.5e1``.
|
Examples include ``2e10``, ``-2e10``, ``2e-10``, ``2.5e1``.
|
||||||
|
|
||||||
Underscores can be used to separate the digits of a numeric literal to aid readability.
|
Underscores can be used to separate the digits of a numeric literal to aid readability.
|
||||||
@ -507,7 +509,7 @@ String literals are written with either double or single-quotes (``"foo"`` or ``
|
|||||||
|
|
||||||
For example, with ``bytes32 samevar = "stringliteral"`` the string literal is interpreted in its raw byte form when assigned to a ``bytes32`` type.
|
For example, with ``bytes32 samevar = "stringliteral"`` the string literal is interpreted in its raw byte form when assigned to a ``bytes32`` type.
|
||||||
|
|
||||||
String literals can only contain printable ASCII characters, which means the characters between and including 0x1F .. 0x7E.
|
String literals can only contain printable ASCII characters, which means the characters between and including 0x20 .. 0x7E.
|
||||||
|
|
||||||
Additionally, string literals also support the following escape characters:
|
Additionally, string literals also support the following escape characters:
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ ABI Encoding and Decoding Functions
|
|||||||
- ``abi.encode(...) returns (bytes memory)``: ABI-encodes the given arguments
|
- ``abi.encode(...) returns (bytes memory)``: ABI-encodes the given arguments
|
||||||
- ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments. Note that packed encoding can be ambiguous!
|
- ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments. Note that packed encoding can be ambiguous!
|
||||||
- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector
|
- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector
|
||||||
- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)```
|
- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)``
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
These encoding functions can be used to craft data for external function calls without actually
|
These encoding functions can be used to craft data for external function calls without actually
|
||||||
|
14
docs/yul.rst
14
docs/yul.rst
@ -166,7 +166,7 @@ Inside a code block, the following elements can be used
|
|||||||
- if statements, e.g. ``if lt(a, b) { sstore(0, 1) }``
|
- if statements, e.g. ``if lt(a, b) { sstore(0, 1) }``
|
||||||
- switch statements, e.g. ``switch mload(0) case 0 { revert() } default { mstore(0, 1) }``
|
- switch statements, e.g. ``switch mload(0) case 0 { revert() } default { mstore(0, 1) }``
|
||||||
- for loops, e.g. ``for { let i := 0} lt(i, 10) { i := add(i, 1) } { mstore(i, 7) }``
|
- for loops, e.g. ``for { let i := 0} lt(i, 10) { i := add(i, 1) } { mstore(i, 7) }``
|
||||||
- function definitions, e.g. ``function f(a, b) -> c { c := add(a, b) }```
|
- function definitions, e.g. ``function f(a, b) -> c { c := add(a, b) }``
|
||||||
|
|
||||||
Multiple syntactical elements can follow each other simply separated by
|
Multiple syntactical elements can follow each other simply separated by
|
||||||
whitespace, i.e. there is no terminating ``;`` or newline required.
|
whitespace, i.e. there is no terminating ``;`` or newline required.
|
||||||
@ -714,13 +714,15 @@ We will use a destructuring notation for the AST nodes.
|
|||||||
L'[$parami] = vi and L'[$reti] = 0 for all i.
|
L'[$parami] = vi and L'[$reti] = 0 for all i.
|
||||||
Let G'', L'', mode = E(Gn, L', block)
|
Let G'', L'', mode = E(Gn, L', block)
|
||||||
G'', Ln, L''[$ret1], ..., L''[$retm]
|
G'', Ln, L''[$ret1], ..., L''[$retm]
|
||||||
E(G, L, l: StringLiteral) = G, L, utf8EncodeLeftAligned(l),
|
E(G, L, l: StringLiteral) = G, L, str(l),
|
||||||
where utf8EncodeLeftAligned performs a UTF-8 encoding of l
|
where str is the string evaluation function,
|
||||||
and aligns it left into 32 bytes
|
which for the EVM dialect is defined in the section 'Literals' above
|
||||||
E(G, L, n: HexNumber) = G, L, hex(n)
|
E(G, L, n: HexNumber) = G, L, hex(n)
|
||||||
where hex is the hexadecimal decoding function
|
where hex is the hexadecimal evaluation function,
|
||||||
|
which turns a sequence of hexadecimal digits into their big endian value
|
||||||
E(G, L, n: DecimalNumber) = G, L, dec(n),
|
E(G, L, n: DecimalNumber) = G, L, dec(n),
|
||||||
where dec is the decimal decoding function
|
where dec is the decimal evaluation function,
|
||||||
|
which turns a sequence of decimal digits into their big endian value
|
||||||
|
|
||||||
.. _opcodes:
|
.. _opcodes:
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ string CharStream::lineAtPosition(int _position) const
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
|
LineColumn CharStream::translatePositionToLineColumn(int _position) const
|
||||||
{
|
{
|
||||||
using size_type = string::size_type;
|
using size_type = string::size_type;
|
||||||
using diff_type = string::difference_type;
|
using diff_type = string::difference_type;
|
||||||
@ -114,7 +114,7 @@ tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
|
|||||||
lineStart = m_source.rfind('\n', searchPosition - 1);
|
lineStart = m_source.rfind('\n', searchPosition - 1);
|
||||||
lineStart = lineStart == string::npos ? 0 : lineStart + 1;
|
lineStart = lineStart == string::npos ? 0 : lineStart + 1;
|
||||||
}
|
}
|
||||||
return tuple<int, int>(lineNumber, searchPosition - lineStart);
|
return LineColumn{lineNumber, static_cast<int>(searchPosition - lineStart)};
|
||||||
}
|
}
|
||||||
|
|
||||||
string_view CharStream::text(SourceLocation const& _location) const
|
string_view CharStream::text(SourceLocation const& _location) const
|
||||||
@ -144,3 +144,32 @@ string CharStream::singleLineSnippet(string const& _sourceCode, SourceLocation c
|
|||||||
|
|
||||||
return cut;
|
return cut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<int> CharStream::translateLineColumnToPosition(LineColumn const& _lineColumn) const
|
||||||
|
{
|
||||||
|
return translateLineColumnToPosition(m_source, _lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<int> CharStream::translateLineColumnToPosition(std::string const& _text, LineColumn const& _input)
|
||||||
|
{
|
||||||
|
if (_input.line < 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
for (int i = 0; i < _input.line; i++)
|
||||||
|
{
|
||||||
|
offset = _text.find('\n', offset);
|
||||||
|
if (offset == _text.npos)
|
||||||
|
return nullopt;
|
||||||
|
offset++; // Skip linefeed.
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t endOfLine = _text.find('\n', offset);
|
||||||
|
if (endOfLine == string::npos)
|
||||||
|
endOfLine = _text.size();
|
||||||
|
|
||||||
|
if (offset + static_cast<size_t>(_input.column) > endOfLine)
|
||||||
|
return nullopt;
|
||||||
|
return offset + static_cast<size_t>(_input.column);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -59,6 +60,7 @@ namespace solidity::langutil
|
|||||||
{
|
{
|
||||||
|
|
||||||
struct SourceLocation;
|
struct SourceLocation;
|
||||||
|
struct LineColumn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bidirectional stream of characters.
|
* Bidirectional stream of characters.
|
||||||
@ -97,9 +99,15 @@ public:
|
|||||||
/// Functions that help pretty-printing parse errors
|
/// Functions that help pretty-printing parse errors
|
||||||
/// Do only use in error cases, they are quite expensive.
|
/// Do only use in error cases, they are quite expensive.
|
||||||
std::string lineAtPosition(int _position) const;
|
std::string lineAtPosition(int _position) const;
|
||||||
std::tuple<int, int> translatePositionToLineColumn(int _position) const;
|
LineColumn translatePositionToLineColumn(int _position) const;
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
/// Translates a line:column to the absolute position.
|
||||||
|
std::optional<int> translateLineColumnToPosition(LineColumn const& _lineColumn) const;
|
||||||
|
|
||||||
|
/// Translates a line:column to the absolute position for the given input text.
|
||||||
|
static std::optional<int> translateLineColumnToPosition(std::string const& _text, LineColumn const& _input);
|
||||||
|
|
||||||
/// Tests whether or not given octet sequence is present at the current position in stream.
|
/// Tests whether or not given octet sequence is present at the current position in stream.
|
||||||
/// @returns true if the sequence could be found, false otherwise.
|
/// @returns true if the sequence could be found, false otherwise.
|
||||||
bool prefixMatch(std::string_view _sequence)
|
bool prefixMatch(std::string_view _sequence)
|
||||||
|
@ -75,6 +75,16 @@ Error::Error(
|
|||||||
*this << util::errinfo_comment(_description);
|
*this << util::errinfo_comment(_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceLocation const* Error::sourceLocation() const noexcept
|
||||||
|
{
|
||||||
|
return boost::get_error_info<errinfo_sourceLocation>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondarySourceLocation const* Error::secondarySourceLocation() const noexcept
|
||||||
|
{
|
||||||
|
return boost::get_error_info<errinfo_secondarySourceLocation>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
optional<Error::Severity> Error::severityFromString(string _input)
|
optional<Error::Severity> Error::severityFromString(string _input)
|
||||||
{
|
{
|
||||||
boost::algorithm::to_lower(_input);
|
boost::algorithm::to_lower(_input);
|
||||||
|
@ -197,6 +197,9 @@ public:
|
|||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
std::string const& typeName() const { return m_typeName; }
|
std::string const& typeName() const { return m_typeName; }
|
||||||
|
|
||||||
|
SourceLocation const* sourceLocation() const noexcept;
|
||||||
|
SecondarySourceLocation const* secondarySourceLocation() const noexcept;
|
||||||
|
|
||||||
/// helper functions
|
/// helper functions
|
||||||
static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type)
|
static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type)
|
||||||
{
|
{
|
||||||
@ -206,7 +209,7 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Severity errorSeverity(Type _type)
|
static constexpr Severity errorSeverity(Type _type)
|
||||||
{
|
{
|
||||||
if (_type == Type::Info)
|
if (_type == Type::Info)
|
||||||
return Severity::Info;
|
return Severity::Info;
|
||||||
|
@ -119,4 +119,23 @@ SourceLocation parseSourceLocation(
|
|||||||
/// Stream output for Location (used e.g. in boost exceptions).
|
/// Stream output for Location (used e.g. in boost exceptions).
|
||||||
std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location);
|
std::ostream& operator<<(std::ostream& _out, SourceLocation const& _location);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative, line-column-based representation for source locations.
|
||||||
|
* Both line and column are zero-based.
|
||||||
|
* If used as a range, the second location is considered exclusive.
|
||||||
|
* Negative values are invalid.
|
||||||
|
*/
|
||||||
|
struct LineColumn
|
||||||
|
{
|
||||||
|
/// Line value, can be between zero and number of `\n` characters in the source file.
|
||||||
|
int line = -1;
|
||||||
|
/// Column value, can be between zero and number of characters in the line (inclusive).
|
||||||
|
int column = -1;
|
||||||
|
|
||||||
|
LineColumn() = default;
|
||||||
|
explicit LineColumn(int _line, int _column): line(_line), column(_column) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,15 +30,6 @@ namespace solidity::langutil
|
|||||||
|
|
||||||
class CharStreamProvider;
|
class CharStreamProvider;
|
||||||
|
|
||||||
struct LineColumn
|
|
||||||
{
|
|
||||||
int line = {-1};
|
|
||||||
int column = {-1};
|
|
||||||
|
|
||||||
LineColumn() = default;
|
|
||||||
LineColumn(std::tuple<int, int> const& _t): line{std::get<0>(_t)}, column{std::get<1>(_t)} {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SourceReference
|
struct SourceReference
|
||||||
{
|
{
|
||||||
std::string message; ///< A message that relates to this source reference (such as a warning, info or an error message).
|
std::string message; ///< A message that relates to this source reference (such as a warning, info or an error message).
|
||||||
|
@ -387,7 +387,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
|||||||
_var.referenceLocation() == VariableDeclaration::Location::Storage &&
|
_var.referenceLocation() == VariableDeclaration::Location::Storage &&
|
||||||
!m_currentContract->abstract()
|
!m_currentContract->abstract()
|
||||||
)
|
)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.fatalTypeError(
|
||||||
3644_error,
|
3644_error,
|
||||||
_var.location(),
|
_var.location(),
|
||||||
"This parameter has a type that can only be used internally. "
|
"This parameter has a type that can only be used internally. "
|
||||||
@ -403,7 +403,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
|||||||
solAssert(!message.empty(), "Expected detailed error message!");
|
solAssert(!message.empty(), "Expected detailed error message!");
|
||||||
if (_function.isConstructor())
|
if (_function.isConstructor())
|
||||||
message += " You can make the contract abstract to avoid this problem.";
|
message += " You can make the contract abstract to avoid this problem.";
|
||||||
m_errorReporter.typeError(4103_error, _var.location(), message);
|
m_errorReporter.fatalTypeError(4103_error, _var.location(), message);
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
!useABICoderV2() &&
|
!useABICoderV2() &&
|
||||||
|
@ -972,8 +972,6 @@ void CHC::resetSourceAnalysis()
|
|||||||
{
|
{
|
||||||
SMTEncoder::resetSourceAnalysis();
|
SMTEncoder::resetSourceAnalysis();
|
||||||
|
|
||||||
m_safeTargets.clear();
|
|
||||||
m_unsafeTargets.clear();
|
|
||||||
m_unprovedTargets.clear();
|
m_unprovedTargets.clear();
|
||||||
m_invariants.clear();
|
m_invariants.clear();
|
||||||
m_functionTargetIds.clear();
|
m_functionTargetIds.clear();
|
||||||
|
@ -129,7 +129,7 @@ Json::Value formatErrorWithException(
|
|||||||
_charStreamProvider
|
_charStreamProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
if (string const* description = boost::get_error_info<util::errinfo_comment>(_exception))
|
if (string const* description = _exception.comment())
|
||||||
message = ((_message.length() > 0) ? (_message + ":") : "") + *description;
|
message = ((_message.length() > 0) ? (_message + ":") : "") + *description;
|
||||||
else
|
else
|
||||||
message = _message;
|
message = _message;
|
||||||
|
@ -79,6 +79,17 @@ string solidity::util::readUntilEnd(istream& _stdin)
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string solidity::util::readBytes(istream& _input, size_t _length)
|
||||||
|
{
|
||||||
|
string output;
|
||||||
|
output.resize(_length);
|
||||||
|
_input.read(output.data(), static_cast<streamsize>(_length));
|
||||||
|
// If read() reads fewer bytes it sets failbit in addition to eofbit.
|
||||||
|
if (_input.fail())
|
||||||
|
output.resize(static_cast<size_t>(_input.gcount()));
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
class DisableConsoleBuffering
|
class DisableConsoleBuffering
|
||||||
{
|
{
|
||||||
|
@ -57,6 +57,10 @@ std::string readFileAsString(boost::filesystem::path const& _file);
|
|||||||
/// Retrieves and returns the whole content of the specified input stream (until EOF).
|
/// Retrieves and returns the whole content of the specified input stream (until EOF).
|
||||||
std::string readUntilEnd(std::istream& _stdin);
|
std::string readUntilEnd(std::istream& _stdin);
|
||||||
|
|
||||||
|
/// Tries to read exactly @a _length bytes from @a _input.
|
||||||
|
/// Returns a string containing as much data as has been read.
|
||||||
|
std::string readBytes(std::istream& _input, size_t _length);
|
||||||
|
|
||||||
/// Retrieves and returns a character from standard input (without waiting for EOL).
|
/// Retrieves and returns a character from standard input (without waiting for EOL).
|
||||||
int readStandardInputChar();
|
int readStandardInputChar();
|
||||||
|
|
||||||
|
@ -39,8 +39,6 @@ struct Exception: virtual std::exception, virtual boost::exception
|
|||||||
|
|
||||||
/// @returns the errinfo_comment of this exception.
|
/// @returns the errinfo_comment of this exception.
|
||||||
std::string const* comment() const noexcept;
|
std::string const* comment() const noexcept;
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Throws an exception with a given description and extra information about the location the
|
/// Throws an exception with a given description and extra information about the location the
|
||||||
@ -56,6 +54,10 @@ private:
|
|||||||
::boost::throw_line(__LINE__) \
|
::boost::throw_line(__LINE__) \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/// Defines an exception type that's meant to signal a specific condition and be caught rather than
|
||||||
|
/// unwind the stack all the way to the top-level exception handler and interrupt the program.
|
||||||
|
/// As such it does not carry a message - the code catching it is expected to handle it without
|
||||||
|
/// letting it escape.
|
||||||
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual ::solidity::util::Exception { const char* what() const noexcept override { return #X; } }
|
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual ::solidity::util::Exception { const char* what() const noexcept override { return #X; } }
|
||||||
|
|
||||||
DEV_SIMPLE_EXCEPTION(InvalidAddress);
|
DEV_SIMPLE_EXCEPTION(InvalidAddress);
|
||||||
|
@ -173,10 +173,10 @@ add_library(yul
|
|||||||
optimiser/OptimizerUtilities.h
|
optimiser/OptimizerUtilities.h
|
||||||
optimiser/ReasoningBasedSimplifier.cpp
|
optimiser/ReasoningBasedSimplifier.cpp
|
||||||
optimiser/ReasoningBasedSimplifier.h
|
optimiser/ReasoningBasedSimplifier.h
|
||||||
optimiser/RedundantAssignEliminator.cpp
|
optimiser/UnusedAssignEliminator.cpp
|
||||||
optimiser/RedundantAssignEliminator.h
|
optimiser/UnusedAssignEliminator.h
|
||||||
optimiser/RedundantStoreBase.cpp
|
optimiser/UnusedStoreBase.cpp
|
||||||
optimiser/RedundantStoreBase.h
|
optimiser/UnusedStoreBase.h
|
||||||
optimiser/Rematerialiser.cpp
|
optimiser/Rematerialiser.cpp
|
||||||
optimiser/Rematerialiser.h
|
optimiser/Rematerialiser.h
|
||||||
optimiser/SMTSolver.cpp
|
optimiser/SMTSolver.cpp
|
||||||
|
@ -137,7 +137,11 @@ void EVMToEwasmTranslator::parsePolyfill()
|
|||||||
string(solidity::yul::wasm::polyfill::Logical) +
|
string(solidity::yul::wasm::polyfill::Logical) +
|
||||||
string(solidity::yul::wasm::polyfill::Memory) +
|
string(solidity::yul::wasm::polyfill::Memory) +
|
||||||
"}", "");
|
"}", "");
|
||||||
m_polyfill = Parser(errorReporter, WasmDialect::instance()).parse(charStream);
|
|
||||||
|
// Passing an empty SourceLocation() here is a workaround to prevent a crash
|
||||||
|
// when compiling from yul->ewasm. We're stripping nativeLocation and
|
||||||
|
// originLocation from the AST (but we only really need to strip nativeLocation)
|
||||||
|
m_polyfill = Parser(errorReporter, WasmDialect::instance(), langutil::SourceLocation()).parse(charStream);
|
||||||
if (!errors.empty())
|
if (!errors.empty())
|
||||||
{
|
{
|
||||||
string message;
|
string message;
|
||||||
|
@ -43,3 +43,15 @@ void BlockFlattener::operator()(Block& _block)
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlockFlattener::run(OptimiserStepContext&, Block& _ast)
|
||||||
|
{
|
||||||
|
BlockFlattener flattener;
|
||||||
|
for (auto& statement: _ast.statements)
|
||||||
|
if (auto* block = get_if<Block>(&statement))
|
||||||
|
flattener(*block);
|
||||||
|
else if (auto* function = get_if<FunctionDefinition>(&statement))
|
||||||
|
flattener(function->body);
|
||||||
|
else
|
||||||
|
yulAssert(false, "BlockFlattener requires the FunctionGrouper.");
|
||||||
|
}
|
||||||
|
@ -27,7 +27,7 @@ class BlockFlattener: public ASTModifier
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr char const* name{"BlockFlattener"};
|
static constexpr char const* name{"BlockFlattener"};
|
||||||
static void run(OptimiserStepContext&, Block& _ast) { BlockFlattener{}(_ast); }
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
void operator()(Block& _block) override;
|
void operator()(Block& _block) override;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <libyul/optimiser/CircularReferencesPruner.h>
|
#include <libyul/optimiser/CircularReferencesPruner.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
|
#include <libyul/optimiser/FunctionGrouper.h>
|
||||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||||
#include <libyul/AST.h>
|
#include <libyul/AST.h>
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ using namespace solidity::yul;
|
|||||||
void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
|
void CircularReferencesPruner::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
CircularReferencesPruner{_context.reservedIdentifiers}(_ast);
|
CircularReferencesPruner{_context.reservedIdentifiers}(_ast);
|
||||||
|
FunctionGrouper::run(_context, _ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CircularReferencesPruner::operator()(Block& _block)
|
void CircularReferencesPruner::operator()(Block& _block)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||||
|
|
||||||
|
#include <libyul/optimiser/FunctionGrouper.h>
|
||||||
#include <libyul/optimiser/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
@ -37,9 +38,10 @@ using namespace std;
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
|
|
||||||
void ExpressionJoiner::run(OptimiserStepContext&, Block& _ast)
|
void ExpressionJoiner::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
ExpressionJoiner{_ast}(_ast);
|
ExpressionJoiner{_ast}(_ast);
|
||||||
|
FunctionGrouper::run(_context, _ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ namespace solidity::yul
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// Removes statements that are just empty blocks (non-recursive).
|
/// Removes statements that are just empty blocks (non-recursive).
|
||||||
|
/// If this is run on the outermost block, the FunctionGrouper should be run afterwards to keep
|
||||||
|
/// the canonical form.
|
||||||
void removeEmptyBlocks(Block& _block);
|
void removeEmptyBlocks(Block& _block);
|
||||||
|
|
||||||
/// Returns true if a given literal can not be used as an identifier.
|
/// Returns true if a given literal can not be used as an identifier.
|
||||||
|
@ -70,7 +70,7 @@ class NameDispenser;
|
|||||||
* variable references can use the SSA variable. The only exception to this rule are
|
* variable references can use the SSA variable. The only exception to this rule are
|
||||||
* for loop conditions, as we cannot insert a variable declaration there.
|
* for loop conditions, as we cannot insert a variable declaration there.
|
||||||
*
|
*
|
||||||
* After this stage, redundantAssignmentRemover is recommended to remove the unnecessary
|
* After this stage, UnusedAssignmentEliminator is recommended to remove the unnecessary
|
||||||
* intermediate assignments.
|
* intermediate assignments.
|
||||||
*
|
*
|
||||||
* This stage provides best results if CSE is run right before it, because
|
* This stage provides best results if CSE is run right before it, because
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
#include <libyul/optimiser/StackLimitEvader.h>
|
#include <libyul/optimiser/StackLimitEvader.h>
|
||||||
#include <libyul/optimiser/StructuralSimplifier.h>
|
#include <libyul/optimiser/StructuralSimplifier.h>
|
||||||
#include <libyul/optimiser/SyntacticalEquality.h>
|
#include <libyul/optimiser/SyntacticalEquality.h>
|
||||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
#include <libyul/optimiser/UnusedAssignEliminator.h>
|
||||||
#include <libyul/optimiser/VarNameCleaner.h>
|
#include <libyul/optimiser/VarNameCleaner.h>
|
||||||
#include <libyul/optimiser/LoadResolver.h>
|
#include <libyul/optimiser/LoadResolver.h>
|
||||||
#include <libyul/optimiser/LoopInvariantCodeMotion.h>
|
#include <libyul/optimiser/LoopInvariantCodeMotion.h>
|
||||||
@ -118,7 +118,7 @@ void OptimiserSuite::run(
|
|||||||
|
|
||||||
// Some steps depend on properties ensured by FunctionHoister, BlockFlattener, FunctionGrouper and
|
// Some steps depend on properties ensured by FunctionHoister, BlockFlattener, FunctionGrouper and
|
||||||
// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
|
// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
|
||||||
suite.runSequence("hfgo", ast);
|
suite.runSequence("hgfo", ast);
|
||||||
|
|
||||||
NameSimplifier::run(suite.m_context, ast);
|
NameSimplifier::run(suite.m_context, ast);
|
||||||
// Now the user-supplied part
|
// Now the user-supplied part
|
||||||
@ -219,7 +219,7 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
|
|||||||
LiteralRematerialiser,
|
LiteralRematerialiser,
|
||||||
LoadResolver,
|
LoadResolver,
|
||||||
LoopInvariantCodeMotion,
|
LoopInvariantCodeMotion,
|
||||||
RedundantAssignEliminator,
|
UnusedAssignEliminator,
|
||||||
ReasoningBasedSimplifier,
|
ReasoningBasedSimplifier,
|
||||||
Rematerialiser,
|
Rematerialiser,
|
||||||
SSAReverser,
|
SSAReverser,
|
||||||
@ -260,7 +260,7 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
|
|||||||
{LoadResolver::name, 'L'},
|
{LoadResolver::name, 'L'},
|
||||||
{LoopInvariantCodeMotion::name, 'M'},
|
{LoopInvariantCodeMotion::name, 'M'},
|
||||||
{ReasoningBasedSimplifier::name, 'R'},
|
{ReasoningBasedSimplifier::name, 'R'},
|
||||||
{RedundantAssignEliminator::name, 'r'},
|
{UnusedAssignEliminator::name, 'r'},
|
||||||
{Rematerialiser::name, 'm'},
|
{Rematerialiser::name, 'm'},
|
||||||
{SSAReverser::name, 'V'},
|
{SSAReverser::name, 'V'},
|
||||||
{SSATransform::name, 'a'},
|
{SSATransform::name, 'a'},
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* until they go out of scope or are re-assigned.
|
* until they go out of scope or are re-assigned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libyul/optimiser/RedundantAssignEliminator.h>
|
#include <libyul/optimiser/UnusedAssignEliminator.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/AST.h>
|
#include <libyul/AST.h>
|
||||||
@ -33,36 +33,36 @@ using namespace std;
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
|
|
||||||
void RedundantAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
void UnusedAssignEliminator::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
RedundantAssignEliminator rae{_context.dialect};
|
UnusedAssignEliminator rae{_context.dialect};
|
||||||
rae(_ast);
|
rae(_ast);
|
||||||
|
|
||||||
StatementRemover remover{rae.m_pendingRemovals};
|
StatementRemover remover{rae.m_pendingRemovals};
|
||||||
remover(_ast);
|
remover(_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Identifier const& _identifier)
|
void UnusedAssignEliminator::operator()(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
changeUndecidedTo(_identifier.name, State::Used);
|
changeUndecidedTo(_identifier.name, State::Used);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(VariableDeclaration const& _variableDeclaration)
|
void UnusedAssignEliminator::operator()(VariableDeclaration const& _variableDeclaration)
|
||||||
{
|
{
|
||||||
RedundantStoreBase::operator()(_variableDeclaration);
|
UnusedStoreBase::operator()(_variableDeclaration);
|
||||||
|
|
||||||
for (auto const& var: _variableDeclaration.variables)
|
for (auto const& var: _variableDeclaration.variables)
|
||||||
m_declaredVariables.emplace(var.name);
|
m_declaredVariables.emplace(var.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Assignment const& _assignment)
|
void UnusedAssignEliminator::operator()(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
visit(*_assignment.value);
|
visit(*_assignment.value);
|
||||||
for (auto const& var: _assignment.variableNames)
|
for (auto const& var: _assignment.variableNames)
|
||||||
changeUndecidedTo(var.name, State::Unused);
|
changeUndecidedTo(var.name, State::Unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDefinition)
|
void UnusedAssignEliminator::operator()(FunctionDefinition const& _functionDefinition)
|
||||||
{
|
{
|
||||||
ScopedSaveAndRestore outerDeclaredVariables(m_declaredVariables, {});
|
ScopedSaveAndRestore outerDeclaredVariables(m_declaredVariables, {});
|
||||||
ScopedSaveAndRestore outerReturnVariables(m_returnVariables, {});
|
ScopedSaveAndRestore outerReturnVariables(m_returnVariables, {});
|
||||||
@ -70,28 +70,28 @@ void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDe
|
|||||||
for (auto const& retParam: _functionDefinition.returnVariables)
|
for (auto const& retParam: _functionDefinition.returnVariables)
|
||||||
m_returnVariables.insert(retParam.name);
|
m_returnVariables.insert(retParam.name);
|
||||||
|
|
||||||
RedundantStoreBase::operator()(_functionDefinition);
|
UnusedStoreBase::operator()(_functionDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Leave const&)
|
void UnusedAssignEliminator::operator()(Leave const&)
|
||||||
{
|
{
|
||||||
for (YulString name: m_returnVariables)
|
for (YulString name: m_returnVariables)
|
||||||
changeUndecidedTo(name, State::Used);
|
changeUndecidedTo(name, State::Used);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Block const& _block)
|
void UnusedAssignEliminator::operator()(Block const& _block)
|
||||||
{
|
{
|
||||||
ScopedSaveAndRestore outerDeclaredVariables(m_declaredVariables, {});
|
ScopedSaveAndRestore outerDeclaredVariables(m_declaredVariables, {});
|
||||||
|
|
||||||
RedundantStoreBase::operator()(_block);
|
UnusedStoreBase::operator()(_block);
|
||||||
|
|
||||||
for (auto const& var: m_declaredVariables)
|
for (auto const& var: m_declaredVariables)
|
||||||
finalize(var, State::Unused);
|
finalize(var, State::Unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::visit(Statement const& _statement)
|
void UnusedAssignEliminator::visit(Statement const& _statement)
|
||||||
{
|
{
|
||||||
RedundantStoreBase::visit(_statement);
|
UnusedStoreBase::visit(_statement);
|
||||||
|
|
||||||
if (auto const* assignment = get_if<Assignment>(&_statement))
|
if (auto const* assignment = get_if<Assignment>(&_statement))
|
||||||
if (assignment->variableNames.size() == 1)
|
if (assignment->variableNames.size() == 1)
|
||||||
@ -99,7 +99,7 @@ void RedundantAssignEliminator::visit(Statement const& _statement)
|
|||||||
m_stores[assignment->variableNames.front().name][&_statement];
|
m_stores[assignment->variableNames.front().name][&_statement];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::shortcutNestedLoop(TrackedStores const& _zeroRuns)
|
void UnusedAssignEliminator::shortcutNestedLoop(TrackedStores const& _zeroRuns)
|
||||||
{
|
{
|
||||||
// Shortcut to avoid horrible runtime:
|
// Shortcut to avoid horrible runtime:
|
||||||
// Change all assignments that were newly introduced in the for loop to "used".
|
// Change all assignments that were newly introduced in the for loop to "used".
|
||||||
@ -116,7 +116,7 @@ void RedundantAssignEliminator::shortcutNestedLoop(TrackedStores const& _zeroRun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::finalizeFunctionDefinition(FunctionDefinition const& _functionDefinition)
|
void UnusedAssignEliminator::finalizeFunctionDefinition(FunctionDefinition const& _functionDefinition)
|
||||||
{
|
{
|
||||||
for (auto const& param: _functionDefinition.parameters)
|
for (auto const& param: _functionDefinition.parameters)
|
||||||
finalize(param.name, State::Unused);
|
finalize(param.name, State::Unused);
|
||||||
@ -124,14 +124,14 @@ void RedundantAssignEliminator::finalizeFunctionDefinition(FunctionDefinition co
|
|||||||
finalize(retParam.name, State::Used);
|
finalize(retParam.name, State::Used);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
|
void UnusedAssignEliminator::changeUndecidedTo(YulString _variable, UnusedAssignEliminator::State _newState)
|
||||||
{
|
{
|
||||||
for (auto& assignment: m_stores[_variable])
|
for (auto& assignment: m_stores[_variable])
|
||||||
if (assignment.second == State::Undecided)
|
if (assignment.second == State::Undecided)
|
||||||
assignment.second = _newState;
|
assignment.second = _newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState)
|
void UnusedAssignEliminator::finalize(YulString _variable, UnusedAssignEliminator::State _finalState)
|
||||||
{
|
{
|
||||||
std::map<Statement const*, State> stores = std::move(m_stores[_variable]);
|
std::map<Statement const*, State> stores = std::move(m_stores[_variable]);
|
||||||
m_stores.erase(_variable);
|
m_stores.erase(_variable);
|
@ -25,7 +25,7 @@
|
|||||||
#include <libyul/ASTForward.h>
|
#include <libyul/ASTForward.h>
|
||||||
#include <libyul/optimiser/ASTWalker.h>
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
#include <libyul/optimiser/OptimiserStep.h>
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/optimiser/RedundantStoreBase.h>
|
#include <libyul/optimiser/UnusedStoreBase.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -107,13 +107,13 @@ struct Dialect;
|
|||||||
*
|
*
|
||||||
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
||||||
*/
|
*/
|
||||||
class RedundantAssignEliminator: public RedundantStoreBase
|
class UnusedAssignEliminator: public UnusedStoreBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr char const* name{"RedundantAssignEliminator"};
|
static constexpr char const* name{"UnusedAssignEliminator"};
|
||||||
static void run(OptimiserStepContext&, Block& _ast);
|
static void run(OptimiserStepContext&, Block& _ast);
|
||||||
|
|
||||||
explicit RedundantAssignEliminator(Dialect const& _dialect): RedundantStoreBase(_dialect) {}
|
explicit UnusedAssignEliminator(Dialect const& _dialect): UnusedStoreBase(_dialect) {}
|
||||||
|
|
||||||
void operator()(Identifier const& _identifier) override;
|
void operator()(Identifier const& _identifier) override;
|
||||||
void operator()(VariableDeclaration const& _variableDeclaration) override;
|
void operator()(VariableDeclaration const& _variableDeclaration) override;
|
||||||
@ -122,7 +122,7 @@ public:
|
|||||||
void operator()(Leave const&) override;
|
void operator()(Leave const&) override;
|
||||||
void operator()(Block const& _block) override;
|
void operator()(Block const& _block) override;
|
||||||
|
|
||||||
using RedundantStoreBase::visit;
|
using UnusedStoreBase::visit;
|
||||||
void visit(Statement const& _statement) override;
|
void visit(Statement const& _statement) override;
|
||||||
|
|
||||||
private:
|
private:
|
@ -21,6 +21,7 @@
|
|||||||
#include <libyul/optimiser/UnusedPruner.h>
|
#include <libyul/optimiser/UnusedPruner.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
|
#include <libyul/optimiser/FunctionGrouper.h>
|
||||||
#include <libyul/optimiser/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/OptimizerUtilities.h>
|
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||||
@ -33,6 +34,12 @@ using namespace std;
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
|
|
||||||
|
void UnusedPruner::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
|
||||||
|
FunctionGrouper::run(_context, _ast);
|
||||||
|
}
|
||||||
|
|
||||||
UnusedPruner::UnusedPruner(
|
UnusedPruner::UnusedPruner(
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
Block& _ast,
|
Block& _ast,
|
||||||
|
@ -50,9 +50,7 @@ class UnusedPruner: public ASTModifier
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr char const* name{"UnusedPruner"};
|
static constexpr char const* name{"UnusedPruner"};
|
||||||
static void run(OptimiserStepContext& _context, Block& _ast) {
|
static void run(OptimiserStepContext& _context, Block& _ast);
|
||||||
UnusedPruner::runUntilStabilisedOnFullAST(_context.dialect, _ast, _context.reservedIdentifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
using ASTModifier::operator();
|
using ASTModifier::operator();
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
/**
|
/**
|
||||||
* Base class for both RedundantAssignEliminator and RedundantStoreEliminator.
|
* Base class for both UnusedAssignEliminator and UnusedStoreEliminator.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libyul/optimiser/RedundantStoreBase.h>
|
#include <libyul/optimiser/UnusedStoreBase.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/OptimiserStep.h>
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
@ -33,7 +33,7 @@ using namespace std;
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
|
|
||||||
void RedundantStoreBase::operator()(If const& _if)
|
void UnusedStoreBase::operator()(If const& _if)
|
||||||
{
|
{
|
||||||
visit(*_if.condition);
|
visit(*_if.condition);
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ void RedundantStoreBase::operator()(If const& _if)
|
|||||||
merge(m_stores, move(skipBranch));
|
merge(m_stores, move(skipBranch));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::operator()(Switch const& _switch)
|
void UnusedStoreBase::operator()(Switch const& _switch)
|
||||||
{
|
{
|
||||||
visit(*_switch.expression);
|
visit(*_switch.expression);
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ void RedundantStoreBase::operator()(Switch const& _switch)
|
|||||||
merge(m_stores, move(branch));
|
merge(m_stores, move(branch));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::operator()(FunctionDefinition const& _functionDefinition)
|
void UnusedStoreBase::operator()(FunctionDefinition const& _functionDefinition)
|
||||||
{
|
{
|
||||||
ScopedSaveAndRestore outerAssignments(m_stores, {});
|
ScopedSaveAndRestore outerAssignments(m_stores, {});
|
||||||
ScopedSaveAndRestore forLoopInfo(m_forLoopInfo, {});
|
ScopedSaveAndRestore forLoopInfo(m_forLoopInfo, {});
|
||||||
@ -79,7 +79,7 @@ void RedundantStoreBase::operator()(FunctionDefinition const& _functionDefinitio
|
|||||||
finalizeFunctionDefinition(_functionDefinition);
|
finalizeFunctionDefinition(_functionDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::operator()(ForLoop const& _forLoop)
|
void UnusedStoreBase::operator()(ForLoop const& _forLoop)
|
||||||
{
|
{
|
||||||
ScopedSaveAndRestore outerForLoopInfo(m_forLoopInfo, {});
|
ScopedSaveAndRestore outerForLoopInfo(m_forLoopInfo, {});
|
||||||
ScopedSaveAndRestore forLoopNestingDepth(m_forLoopNestingDepth, m_forLoopNestingDepth + 1);
|
ScopedSaveAndRestore forLoopNestingDepth(m_forLoopNestingDepth, m_forLoopNestingDepth + 1);
|
||||||
@ -127,19 +127,19 @@ void RedundantStoreBase::operator()(ForLoop const& _forLoop)
|
|||||||
m_forLoopInfo.pendingBreakStmts.clear();
|
m_forLoopInfo.pendingBreakStmts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::operator()(Break const&)
|
void UnusedStoreBase::operator()(Break const&)
|
||||||
{
|
{
|
||||||
m_forLoopInfo.pendingBreakStmts.emplace_back(move(m_stores));
|
m_forLoopInfo.pendingBreakStmts.emplace_back(move(m_stores));
|
||||||
m_stores.clear();
|
m_stores.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::operator()(Continue const&)
|
void UnusedStoreBase::operator()(Continue const&)
|
||||||
{
|
{
|
||||||
m_forLoopInfo.pendingContinueStmts.emplace_back(move(m_stores));
|
m_forLoopInfo.pendingContinueStmts.emplace_back(move(m_stores));
|
||||||
m_stores.clear();
|
m_stores.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::merge(TrackedStores& _target, TrackedStores&& _other)
|
void UnusedStoreBase::merge(TrackedStores& _target, TrackedStores&& _other)
|
||||||
{
|
{
|
||||||
util::joinMap(_target, move(_other), [](
|
util::joinMap(_target, move(_other), [](
|
||||||
map<Statement const*, State>& _assignmentHere,
|
map<Statement const*, State>& _assignmentHere,
|
||||||
@ -150,7 +150,7 @@ void RedundantStoreBase::merge(TrackedStores& _target, TrackedStores&& _other)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantStoreBase::merge(TrackedStores& _target, vector<TrackedStores>&& _source)
|
void UnusedStoreBase::merge(TrackedStores& _target, vector<TrackedStores>&& _source)
|
||||||
{
|
{
|
||||||
for (TrackedStores& ts: _source)
|
for (TrackedStores& ts: _source)
|
||||||
merge(_target, move(ts));
|
merge(_target, move(ts));
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
/**
|
/**
|
||||||
* Base class for both RedundantAssignEliminator and RedundantStoreEliminator.
|
* Base class for both UnusedAssignEliminator and UnusedStoreEliminator.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -34,14 +34,19 @@ namespace solidity::yul
|
|||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for both RedundantAssignEliminator and RedundantStoreEliminator.
|
* Base class for both UnusedAssignEliminator and UnusedStoreEliminator.
|
||||||
|
*
|
||||||
|
* The class tracks the state of abstract "stores" (assignments or mstore/sstore
|
||||||
|
* statements) across the control-flow. It is the job of the derived class to create
|
||||||
|
* the stores and track references, but the base class adjusts their "used state" at
|
||||||
|
* control-flow splits and joins.
|
||||||
*
|
*
|
||||||
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
* Prerequisite: Disambiguator, ForLoopInitRewriter.
|
||||||
*/
|
*/
|
||||||
class RedundantStoreBase: public ASTWalker
|
class UnusedStoreBase: public ASTWalker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit RedundantStoreBase(Dialect const& _dialect): m_dialect(_dialect) {}
|
explicit UnusedStoreBase(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||||
|
|
||||||
using ASTWalker::operator();
|
using ASTWalker::operator();
|
||||||
void operator()(If const& _if) override;
|
void operator()(If const& _if) override;
|
@ -34,7 +34,7 @@ else
|
|||||||
BUILD_DIR="$1"
|
BUILD_DIR="$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:emscripten-7
|
# solbuildpackpusher/solidity-buildpack-deps:emscripten-8
|
||||||
docker run -v "$(pwd):/root/project" -w /root/project \
|
docker run -v "$(pwd):/root/project" -w /root/project \
|
||||||
solbuildpackpusher/solidity-buildpack-deps@sha256:9ffcd0944433fe100e9433f2aa9ba5c21e096e758ad8a05a4a76feaed3d1f463 \
|
solbuildpackpusher/solidity-buildpack-deps@sha256:842d6074e0e7e5355c89122c1cafc1fdb59696596750e7d56e5f35c0d883ad59 \
|
||||||
./scripts/ci/build_emscripten.sh "$BUILD_DIR"
|
./scripts/ci/build_emscripten.sh "$BUILD_DIR"
|
||||||
|
@ -171,6 +171,18 @@ function msg_on_error
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function diff_values
|
||||||
|
{
|
||||||
|
(( $# >= 2 )) || fail "diff_values requires at least 2 arguments."
|
||||||
|
|
||||||
|
local value1="$1"
|
||||||
|
local value2="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
|
||||||
|
diff --color=auto --unified=0 <(echo "$value1") <(echo "$value2") "$@"
|
||||||
|
}
|
||||||
|
|
||||||
function safe_kill
|
function safe_kill
|
||||||
{
|
{
|
||||||
local PID=${1}
|
local PID=${1}
|
||||||
@ -196,3 +208,25 @@ function safe_kill
|
|||||||
kill -9 "$PID"
|
kill -9 "$PID"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function circleci_select_steps
|
||||||
|
{
|
||||||
|
local all_steps="$1"
|
||||||
|
(( $# == 1 )) || assertFail
|
||||||
|
|
||||||
|
if (( CIRCLE_NODE_TOTAL )) && (( CIRCLE_NODE_TOTAL > 1 ))
|
||||||
|
then
|
||||||
|
echo "$all_steps" | circleci tests split | xargs
|
||||||
|
else
|
||||||
|
echo "$all_steps" | xargs
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function circleci_step_selected
|
||||||
|
{
|
||||||
|
local selected_steps="$1"
|
||||||
|
local step="$2"
|
||||||
|
[[ $step != *" "* ]] || assertFail "Step names must not contain spaces."
|
||||||
|
|
||||||
|
[[ " $selected_steps " == *" $step "* ]] || return 1
|
||||||
|
}
|
||||||
|
@ -25,7 +25,7 @@ set -ev
|
|||||||
keyid=70D110489D66E2F6
|
keyid=70D110489D66E2F6
|
||||||
email=builds@ethereum.org
|
email=builds@ethereum.org
|
||||||
packagename=z3-static
|
packagename=z3-static
|
||||||
version=4.8.12
|
version=4.8.13
|
||||||
|
|
||||||
DISTRIBUTIONS="focal groovy hirsute"
|
DISTRIBUTIONS="focal groovy hirsute"
|
||||||
|
|
||||||
|
@ -33,12 +33,12 @@
|
|||||||
# Using $(em-config CACHE)/sysroot/usr seems to work, though, and still has cmake find the
|
# Using $(em-config CACHE)/sysroot/usr seems to work, though, and still has cmake find the
|
||||||
# dependencies automatically.
|
# dependencies automatically.
|
||||||
FROM emscripten/emsdk:2.0.33 AS base
|
FROM emscripten/emsdk:2.0.33 AS base
|
||||||
LABEL version="7"
|
LABEL version="8"
|
||||||
|
|
||||||
ADD emscripten.jam /usr/src
|
ADD emscripten.jam /usr/src
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
cd /usr/src; \
|
cd /usr/src; \
|
||||||
git clone https://github.com/Z3Prover/z3.git -b z3-4.8.12 --depth 1 ; \
|
git clone https://github.com/Z3Prover/z3.git -b z3-4.8.13 --depth 1 ; \
|
||||||
cd z3; \
|
cd z3; \
|
||||||
mkdir build; \
|
mkdir build; \
|
||||||
cd build; \
|
cd build; \
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2021 solidity contributors.
|
# (c) 2016-2021 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM gcr.io/oss-fuzz-base/base-clang:latest as base
|
FROM gcr.io/oss-fuzz-base/base-clang:latest as base
|
||||||
LABEL version="13"
|
LABEL version="14"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ RUN set -ex; \
|
|||||||
|
|
||||||
# Z3
|
# Z3
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
git clone --depth 1 -b z3-4.8.12 https://github.com/Z3Prover/z3.git \
|
git clone --depth 1 -b z3-4.8.13 https://github.com/Z3Prover/z3.git \
|
||||||
/usr/src/z3; \
|
/usr/src/z3; \
|
||||||
cd /usr/src/z3; \
|
cd /usr/src/z3; \
|
||||||
mkdir build; \
|
mkdir build; \
|
||||||
@ -102,18 +102,6 @@ RUN set -ex; \
|
|||||||
ninja install/strip; \
|
ninja install/strip; \
|
||||||
rm -rf /usr/src/evmone
|
rm -rf /usr/src/evmone
|
||||||
|
|
||||||
# HERA
|
|
||||||
RUN set -ex; \
|
|
||||||
cd /usr/src; \
|
|
||||||
git clone --branch="v0.5.0" --depth 1 --recurse-submodules https://github.com/ewasm/hera.git; \
|
|
||||||
cd hera; \
|
|
||||||
mkdir build; \
|
|
||||||
cd build; \
|
|
||||||
cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="/usr" ..; \
|
|
||||||
ninja; \
|
|
||||||
ninja install/strip; \
|
|
||||||
rm -rf /usr/src/hera
|
|
||||||
|
|
||||||
# gmp
|
# gmp
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
# Replace system installed libgmp static library
|
# Replace system installed libgmp static library
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:focal AS base
|
FROM buildpack-deps:focal AS base
|
||||||
LABEL version="8"
|
LABEL version="9"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:focal AS base
|
FROM buildpack-deps:focal AS base
|
||||||
LABEL version="8"
|
LABEL version="9"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
set(libsolcli_sources
|
set(libsolcli_sources
|
||||||
CommandLineInterface.cpp CommandLineInterface.h
|
CommandLineInterface.cpp CommandLineInterface.h
|
||||||
CommandLineParser.cpp CommandLineParser.h
|
CommandLineParser.cpp CommandLineParser.h
|
||||||
|
Exceptions.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(solcli ${libsolcli_sources})
|
add_library(solcli ${libsolcli_sources})
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
#include <solc/CommandLineInterface.h>
|
#include <solc/CommandLineInterface.h>
|
||||||
|
|
||||||
|
#include <solc/Exceptions.h>
|
||||||
|
|
||||||
#include "license.h"
|
#include "license.h"
|
||||||
#include "solidity/BuildInfo.h"
|
#include "solidity/BuildInfo.h"
|
||||||
|
|
||||||
@ -402,7 +404,7 @@ void CommandLineInterface::handleGasEstimation(string const& _contract)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::readInputFiles()
|
void CommandLineInterface::readInputFiles()
|
||||||
{
|
{
|
||||||
solAssert(!m_standardJsonInput.has_value(), "");
|
solAssert(!m_standardJsonInput.has_value(), "");
|
||||||
|
|
||||||
@ -411,23 +413,17 @@ bool CommandLineInterface::readInputFiles()
|
|||||||
m_options.input.mode == InputMode::License ||
|
m_options.input.mode == InputMode::License ||
|
||||||
m_options.input.mode == InputMode::Version
|
m_options.input.mode == InputMode::Version
|
||||||
)
|
)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
m_fileReader.setBasePath(m_options.input.basePath);
|
m_fileReader.setBasePath(m_options.input.basePath);
|
||||||
|
|
||||||
if (m_fileReader.basePath() != "")
|
if (m_fileReader.basePath() != "")
|
||||||
{
|
{
|
||||||
if (!boost::filesystem::exists(m_fileReader.basePath()))
|
if (!boost::filesystem::exists(m_fileReader.basePath()))
|
||||||
{
|
solThrow(CommandLineValidationError, "Base path does not exist: \"" + m_fileReader.basePath().string() + '"');
|
||||||
serr() << "Base path does not exist: " << m_fileReader.basePath() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!boost::filesystem::is_directory(m_fileReader.basePath()))
|
if (!boost::filesystem::is_directory(m_fileReader.basePath()))
|
||||||
{
|
solThrow(CommandLineValidationError, "Base path is not a directory: \"" + m_fileReader.basePath().string() + '"');
|
||||||
serr() << "Base path is not a directory: " << m_fileReader.basePath() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (boost::filesystem::path const& includePath: m_options.input.includePaths)
|
for (boost::filesystem::path const& includePath: m_options.input.includePaths)
|
||||||
@ -442,16 +438,18 @@ bool CommandLineInterface::readInputFiles()
|
|||||||
{
|
{
|
||||||
auto pathToQuotedString = [](boost::filesystem::path const& _path){ return "\"" + _path.string() + "\""; };
|
auto pathToQuotedString = [](boost::filesystem::path const& _path){ return "\"" + _path.string() + "\""; };
|
||||||
|
|
||||||
serr() << "Source unit name collision detected. ";
|
string message =
|
||||||
serr() << "The specified values of base path and/or include paths would result in multiple ";
|
"Source unit name collision detected. "
|
||||||
serr() << "input files being assigned the same source unit name:" << endl;
|
"The specified values of base path and/or include paths would result in multiple "
|
||||||
|
"input files being assigned the same source unit name:\n";
|
||||||
|
|
||||||
for (auto const& [sourceUnitName, normalizedInputPaths]: collisions)
|
for (auto const& [sourceUnitName, normalizedInputPaths]: collisions)
|
||||||
{
|
{
|
||||||
serr() << sourceUnitName << " matches: ";
|
message += sourceUnitName + " matches: ";
|
||||||
serr() << joinHumanReadable(normalizedInputPaths | ranges::views::transform(pathToQuotedString)) << endl;
|
message += joinHumanReadable(normalizedInputPaths | ranges::views::transform(pathToQuotedString)) + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
solThrow(CommandLineValidationError, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (boost::filesystem::path const& infile: m_options.input.paths)
|
for (boost::filesystem::path const& infile: m_options.input.paths)
|
||||||
@ -459,10 +457,7 @@ bool CommandLineInterface::readInputFiles()
|
|||||||
if (!boost::filesystem::exists(infile))
|
if (!boost::filesystem::exists(infile))
|
||||||
{
|
{
|
||||||
if (!m_options.input.ignoreMissingFiles)
|
if (!m_options.input.ignoreMissingFiles)
|
||||||
{
|
solThrow(CommandLineValidationError, '"' + infile.string() + "\" is not found.");
|
||||||
serr() << infile << " is not found." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
serr() << infile << " is not found. Skipping." << endl;
|
serr() << infile << " is not found. Skipping." << endl;
|
||||||
|
|
||||||
@ -472,10 +467,7 @@ bool CommandLineInterface::readInputFiles()
|
|||||||
if (!boost::filesystem::is_regular_file(infile))
|
if (!boost::filesystem::is_regular_file(infile))
|
||||||
{
|
{
|
||||||
if (!m_options.input.ignoreMissingFiles)
|
if (!m_options.input.ignoreMissingFiles)
|
||||||
{
|
solThrow(CommandLineValidationError, '"' + infile.string() + "\" is not a valid file.");
|
||||||
serr() << infile << " is not a valid file." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
serr() << infile << " is not a valid file. Skipping." << endl;
|
serr() << infile << " is not a valid file. Skipping." << endl;
|
||||||
|
|
||||||
@ -508,12 +500,7 @@ bool CommandLineInterface::readInputFiles()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_fileReader.sourceCodes().empty() && !m_standardJsonInput.has_value())
|
if (m_fileReader.sourceCodes().empty() && !m_standardJsonInput.has_value())
|
||||||
{
|
solThrow(CommandLineValidationError, "All specified input files either do not exist or are not regular files.");
|
||||||
serr() << "All specified input files either do not exist or are not regular files." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map<string, Json::Value> CommandLineInterface::parseAstFromInput()
|
map<string, Json::Value> CommandLineInterface::parseAstFromInput()
|
||||||
@ -559,19 +546,12 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da
|
|||||||
|
|
||||||
string pathName = (m_options.output.dir / _fileName).string();
|
string pathName = (m_options.output.dir / _fileName).string();
|
||||||
if (fs::exists(pathName) && !m_options.output.overwriteFiles)
|
if (fs::exists(pathName) && !m_options.output.overwriteFiles)
|
||||||
{
|
solThrow(CommandLineOutputError, "Refusing to overwrite existing file \"" + pathName + "\" (use --overwrite to force).");
|
||||||
serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --overwrite to force)." << endl;
|
|
||||||
m_outputFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ofstream outFile(pathName);
|
ofstream outFile(pathName);
|
||||||
outFile << _data;
|
outFile << _data;
|
||||||
if (!outFile)
|
if (!outFile)
|
||||||
{
|
solThrow(CommandLineOutputError, "Could not write to file \"" + pathName + "\".");
|
||||||
serr() << "Could not write to file \"" << pathName << "\"." << endl;
|
|
||||||
m_outputFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::createJson(string const& _fileName, string const& _json)
|
void CommandLineInterface::createJson(string const& _fileName, string const& _json)
|
||||||
@ -579,9 +559,33 @@ void CommandLineInterface::createJson(string const& _fileName, string const& _js
|
|||||||
createFile(boost::filesystem::basename(_fileName) + string(".json"), _json);
|
createFile(boost::filesystem::basename(_fileName) + string(".json"), _json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CommandLineInterface::run(int _argc, char const* const* _argv)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!parseArguments(_argc, _argv))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
readInputFiles();
|
||||||
|
processInput();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (CommandLineError const& _exception)
|
||||||
|
{
|
||||||
|
m_hasOutput = true;
|
||||||
|
|
||||||
|
// There might be no message in the exception itself if the error output is bulky and has
|
||||||
|
// already been printed to stderr (this happens e.g. for compiler errors).
|
||||||
|
if (_exception.what() != ""s)
|
||||||
|
serr() << _exception.what() << endl;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
||||||
{
|
{
|
||||||
CommandLineParser parser(serr(/* _markAsUsed */ false));
|
CommandLineParser parser;
|
||||||
|
|
||||||
if (isatty(fileno(stdin)) && _argc == 1)
|
if (isatty(fileno(stdin)) && _argc == 1)
|
||||||
{
|
{
|
||||||
@ -592,16 +596,13 @@ bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = parser.parse(_argc, _argv);
|
parser.parse(_argc, _argv);
|
||||||
if (!success)
|
|
||||||
return false;
|
|
||||||
m_hasOutput = m_hasOutput || parser.hasOutput();
|
|
||||||
m_options = parser.options();
|
m_options = parser.options();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::processInput()
|
void CommandLineInterface::processInput()
|
||||||
{
|
{
|
||||||
switch (m_options.input.mode)
|
switch (m_options.input.mode)
|
||||||
{
|
{
|
||||||
@ -624,22 +625,17 @@ bool CommandLineInterface::processInput()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InputMode::Assembler:
|
case InputMode::Assembler:
|
||||||
if (!assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine))
|
assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine);
|
||||||
return false;
|
|
||||||
break;
|
break;
|
||||||
case InputMode::Linker:
|
case InputMode::Linker:
|
||||||
if (!link())
|
link();
|
||||||
return false;
|
|
||||||
writeLinkedFiles();
|
writeLinkedFiles();
|
||||||
break;
|
break;
|
||||||
case InputMode::Compiler:
|
case InputMode::Compiler:
|
||||||
case InputMode::CompilerWithASTImport:
|
case InputMode::CompilerWithASTImport:
|
||||||
if (!compile())
|
compile();
|
||||||
return false;
|
|
||||||
outputCompilationResults();
|
outputCompilationResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !m_outputFailed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::printVersion()
|
void CommandLineInterface::printVersion()
|
||||||
@ -655,7 +651,7 @@ void CommandLineInterface::printLicense()
|
|||||||
sout() << licenseText << endl;
|
sout() << licenseText << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::compile()
|
void CommandLineInterface::compile()
|
||||||
{
|
{
|
||||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
||||||
|
|
||||||
@ -718,8 +714,9 @@ bool CommandLineInterface::compile()
|
|||||||
}
|
}
|
||||||
catch (Exception const& _exc)
|
catch (Exception const& _exc)
|
||||||
{
|
{
|
||||||
serr() << string("Failed to import AST: ") << _exc.what() << endl;
|
// FIXME: AST import is missing proper validations. This hack catches failing
|
||||||
return false;
|
// assertions and presents them as if they were compiler errors.
|
||||||
|
solThrow(CommandLineExecutionError, "Failed to import AST: "s + _exc.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -736,29 +733,29 @@ bool CommandLineInterface::compile()
|
|||||||
formatter.printErrorInformation(*error);
|
formatter.printErrorInformation(*error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!successful)
|
if (!successful && !m_options.input.errorRecovery)
|
||||||
return m_options.input.errorRecovery;
|
solThrow(CommandLineExecutionError, "");
|
||||||
}
|
}
|
||||||
catch (CompilerError const& _exception)
|
catch (CompilerError const& _exception)
|
||||||
{
|
{
|
||||||
m_hasOutput = true;
|
m_hasOutput = true;
|
||||||
formatter.printExceptionInformation(_exception, "Compiler error");
|
formatter.printExceptionInformation(_exception, "Compiler error");
|
||||||
return false;
|
solThrow(CommandLineExecutionError, "");
|
||||||
}
|
}
|
||||||
catch (Error const& _error)
|
catch (Error const& _error)
|
||||||
{
|
{
|
||||||
if (_error.type() == Error::Type::DocstringParsingError)
|
if (_error.type() == Error::Type::DocstringParsingError)
|
||||||
serr() << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_error) << endl;
|
{
|
||||||
|
serr() << *boost::get_error_info<errinfo_comment>(_error);
|
||||||
|
solThrow(CommandLineExecutionError, "Documentation parsing failed.");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_hasOutput = true;
|
m_hasOutput = true;
|
||||||
formatter.printExceptionInformation(_error, _error.typeName());
|
formatter.printExceptionInformation(_error, _error.typeName());
|
||||||
|
solThrow(CommandLineExecutionError, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::handleCombinedJSON()
|
void CommandLineInterface::handleCombinedJSON()
|
||||||
@ -887,7 +884,7 @@ void CommandLineInterface::handleAst()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::link()
|
void CommandLineInterface::link()
|
||||||
{
|
{
|
||||||
solAssert(m_options.input.mode == InputMode::Linker, "");
|
solAssert(m_options.input.mode == InputMode::Linker, "");
|
||||||
|
|
||||||
@ -925,11 +922,11 @@ bool CommandLineInterface::link()
|
|||||||
*(it + placeholderSize - 2) != '_' ||
|
*(it + placeholderSize - 2) != '_' ||
|
||||||
*(it + placeholderSize - 1) != '_'
|
*(it + placeholderSize - 1) != '_'
|
||||||
)
|
)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Error in binary object file " << src.first << " at position " << (it - src.second.begin()) << endl;
|
CommandLineExecutionError,
|
||||||
serr() << '"' << string(it, it + min(placeholderSize, static_cast<int>(end - it))) << "\" is not a valid link reference." << endl;
|
"Error in binary object file " + src.first + " at position " + to_string(it - src.second.begin()) + "\n" +
|
||||||
return false;
|
'"' + string(it, it + min(placeholderSize, static_cast<int>(end - it))) + "\" is not a valid link reference."
|
||||||
}
|
);
|
||||||
|
|
||||||
string foundPlaceholder(it, it + placeholderSize);
|
string foundPlaceholder(it, it + placeholderSize);
|
||||||
if (librariesReplacements.count(foundPlaceholder))
|
if (librariesReplacements.count(foundPlaceholder))
|
||||||
@ -948,8 +945,6 @@ bool CommandLineInterface::link()
|
|||||||
src.second.resize(src.second.size() - 1);
|
src.second.resize(src.second.size() - 1);
|
||||||
}
|
}
|
||||||
m_fileReader.setSources(move(sourceCodes));
|
m_fileReader.setSources(move(sourceCodes));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::writeLinkedFiles()
|
void CommandLineInterface::writeLinkedFiles()
|
||||||
@ -964,11 +959,7 @@ void CommandLineInterface::writeLinkedFiles()
|
|||||||
ofstream outFile(src.first);
|
ofstream outFile(src.first);
|
||||||
outFile << src.second;
|
outFile << src.second;
|
||||||
if (!outFile)
|
if (!outFile)
|
||||||
{
|
solThrow(CommandLineOutputError, "Could not write to file " + src.first + ". Aborting.");
|
||||||
serr() << "Could not write to file " << src.first << ". Aborting." << endl;
|
|
||||||
m_outputFailed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sout() << "Linking completed." << endl;
|
sout() << "Linking completed." << endl;
|
||||||
}
|
}
|
||||||
@ -990,10 +981,12 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine)
|
void CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine)
|
||||||
{
|
{
|
||||||
solAssert(m_options.input.mode == InputMode::Assembler, "");
|
solAssert(m_options.input.mode == InputMode::Assembler, "");
|
||||||
|
|
||||||
|
serr() << "Warning: Yul is still experimental. Please use the output with care." << endl;
|
||||||
|
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
map<string, yul::AssemblyStack> assemblyStacks;
|
map<string, yul::AssemblyStack> assemblyStacks;
|
||||||
for (auto const& src: m_fileReader.sourceCodes())
|
for (auto const& src: m_fileReader.sourceCodes())
|
||||||
@ -1031,7 +1024,10 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!successful)
|
if (!successful)
|
||||||
return false;
|
{
|
||||||
|
solAssert(m_hasOutput);
|
||||||
|
solThrow(CommandLineExecutionError, "");
|
||||||
|
}
|
||||||
|
|
||||||
for (auto const& src: m_fileReader.sourceCodes())
|
for (auto const& src: m_fileReader.sourceCodes())
|
||||||
{
|
{
|
||||||
@ -1089,8 +1085,6 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:
|
|||||||
serr() << "No text representation found." << endl;
|
serr() << "No text representation found." << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::outputCompilationResults()
|
void CommandLineInterface::outputCompilationResults()
|
||||||
@ -1127,14 +1121,10 @@ void CommandLineInterface::outputCompilationResults()
|
|||||||
ret = m_compiler->assemblyString(contract, m_fileReader.sourceCodes());
|
ret = m_compiler->assemblyString(contract, m_fileReader.sourceCodes());
|
||||||
|
|
||||||
if (!m_options.output.dir.empty())
|
if (!m_options.output.dir.empty())
|
||||||
{
|
|
||||||
createFile(m_compiler->filesystemFriendlyName(contract) + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), ret);
|
createFile(m_compiler->filesystemFriendlyName(contract) + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), ret);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
sout() << "EVM assembly:" << endl << ret << endl;
|
sout() << "EVM assembly:" << endl << ret << endl;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (m_options.compiler.estimateGas)
|
if (m_options.compiler.estimateGas)
|
||||||
handleGasEstimation(contract);
|
handleGasEstimation(contract);
|
||||||
|
@ -51,12 +51,28 @@ public:
|
|||||||
m_options(_options)
|
m_options(_options)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// Parse command line arguments and return false if we should not continue
|
/// Parses command-line arguments, executes the requested operation and handles validation and
|
||||||
|
/// execution errors.
|
||||||
|
/// @returns false if it catches a @p CommandLineValidationError or if the application is
|
||||||
|
/// expected to exit with a non-zero exit code despite there being no error.
|
||||||
|
bool run(int _argc, char const* const* _argv);
|
||||||
|
|
||||||
|
/// Parses command line arguments and stores the result in @p m_options.
|
||||||
|
/// @throws CommandLineValidationError if command-line arguments are invalid.
|
||||||
|
/// @returns false if the application is expected to exit with a non-zero exit code despite
|
||||||
|
/// there being no error.
|
||||||
bool parseArguments(int _argc, char const* const* _argv);
|
bool parseArguments(int _argc, char const* const* _argv);
|
||||||
/// Read the content of all input files and initialize the file reader.
|
|
||||||
bool readInputFiles();
|
/// Reads the content of all input files and initializes the file reader.
|
||||||
/// Parse the files, create source code objects, print the output.
|
/// @throws CommandLineValidationError if it fails to read the input files (invalid paths,
|
||||||
bool processInput();
|
/// non-existent files, not enough or too many input files, etc.).
|
||||||
|
void readInputFiles();
|
||||||
|
|
||||||
|
/// Executes the requested operation (compilation, assembling, standard JSON, etc.) and prints
|
||||||
|
/// results to the terminal.
|
||||||
|
/// @throws CommandLineExecutionError if execution fails due to errors in the input files.
|
||||||
|
/// @throws CommandLineOutputError if creating output files or writing to them fails.
|
||||||
|
void processInput();
|
||||||
|
|
||||||
CommandLineOptions const& options() const { return m_options; }
|
CommandLineOptions const& options() const { return m_options; }
|
||||||
FileReader const& fileReader() const { return m_fileReader; }
|
FileReader const& fileReader() const { return m_fileReader; }
|
||||||
@ -65,15 +81,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
void printVersion();
|
void printVersion();
|
||||||
void printLicense();
|
void printLicense();
|
||||||
bool compile();
|
void compile();
|
||||||
bool link();
|
void link();
|
||||||
void writeLinkedFiles();
|
void writeLinkedFiles();
|
||||||
/// @returns the ``// <identifier> -> name`` hint for library placeholders.
|
/// @returns the ``// <identifier> -> name`` hint for library placeholders.
|
||||||
static std::string libraryPlaceholderHint(std::string const& _libraryName);
|
static std::string libraryPlaceholderHint(std::string const& _libraryName);
|
||||||
/// @returns the full object with library placeholder hints in hex.
|
/// @returns the full object with library placeholder hints in hex.
|
||||||
static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj);
|
static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj);
|
||||||
|
|
||||||
bool assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine);
|
void assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine);
|
||||||
|
|
||||||
void outputCompilationResults();
|
void outputCompilationResults();
|
||||||
|
|
||||||
@ -120,7 +136,6 @@ private:
|
|||||||
std::ostream& m_sout;
|
std::ostream& m_sout;
|
||||||
std::ostream& m_serr;
|
std::ostream& m_serr;
|
||||||
bool m_hasOutput = false;
|
bool m_hasOutput = false;
|
||||||
bool m_outputFailed = false; ///< If true, creation or write to some of the output files failed.
|
|
||||||
FileReader m_fileReader;
|
FileReader m_fileReader;
|
||||||
std::optional<std::string> m_standardJsonInput;
|
std::optional<std::string> m_standardJsonInput;
|
||||||
std::unique_ptr<frontend::CompilerStack> m_compiler;
|
std::unique_ptr<frontend::CompilerStack> m_compiler;
|
||||||
|
@ -17,7 +17,11 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
#include <solc/CommandLineParser.h>
|
#include <solc/CommandLineParser.h>
|
||||||
|
|
||||||
|
#include <solc/Exceptions.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/Suite.h>
|
#include <libyul/optimiser/Suite.h>
|
||||||
|
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
@ -34,14 +38,6 @@ namespace po = boost::program_options;
|
|||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
|
|
||||||
ostream& CommandLineParser::serr()
|
|
||||||
{
|
|
||||||
m_hasOutput = true;
|
|
||||||
return m_serr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define cerr
|
|
||||||
|
|
||||||
static string const g_strAllowPaths = "allow-paths";
|
static string const g_strAllowPaths = "allow-paths";
|
||||||
static string const g_strBasePath = "base-path";
|
static string const g_strBasePath = "base-path";
|
||||||
static string const g_strIncludePath = "include-path";
|
static string const g_strIncludePath = "include-path";
|
||||||
@ -131,6 +127,9 @@ static set<string> const g_metadataHashArgs
|
|||||||
};
|
};
|
||||||
|
|
||||||
static map<InputMode, string> const g_inputModeName = {
|
static map<InputMode, string> const g_inputModeName = {
|
||||||
|
{InputMode::Help, "help"},
|
||||||
|
{InputMode::License, "license"},
|
||||||
|
{InputMode::Version, "version"},
|
||||||
{InputMode::Compiler, "compiler"},
|
{InputMode::Compiler, "compiler"},
|
||||||
{InputMode::CompilerWithASTImport, "compiler (AST import)"},
|
{InputMode::CompilerWithASTImport, "compiler (AST import)"},
|
||||||
{InputMode::Assembler, "assembler"},
|
{InputMode::Assembler, "assembler"},
|
||||||
@ -138,15 +137,16 @@ static map<InputMode, string> const g_inputModeName = {
|
|||||||
{InputMode::Linker, "linker"},
|
{InputMode::Linker, "linker"},
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
|
void CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
|
||||||
{
|
{
|
||||||
if (countEnabledOptions(_optionNames) > 1)
|
if (countEnabledOptions(_optionNames) > 1)
|
||||||
{
|
{
|
||||||
serr() << "The following options are mutually exclusive: " << joinOptionNames(_optionNames) << ". ";
|
solThrow(
|
||||||
serr() << "Select at most one." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"The following options are mutually exclusive: " + joinOptionNames(_optionNames) + ". " +
|
||||||
|
"Select at most one."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompilerOutputs::operator==(CompilerOutputs const& _other) const noexcept
|
bool CompilerOutputs::operator==(CompilerOutputs const& _other) const noexcept
|
||||||
@ -268,17 +268,13 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const
|
|||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parse(int _argc, char const* const* _argv)
|
void CommandLineParser::parse(int _argc, char const* const* _argv)
|
||||||
{
|
{
|
||||||
m_hasOutput = false;
|
parseArgs(_argc, _argv);
|
||||||
|
processArgs();
|
||||||
if (!parseArgs(_argc, _argv))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return processArgs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parseInputPathsAndRemappings()
|
void CommandLineParser::parseInputPathsAndRemappings()
|
||||||
{
|
{
|
||||||
m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0);
|
m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0);
|
||||||
|
|
||||||
@ -289,17 +285,14 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
|||||||
{
|
{
|
||||||
optional<ImportRemapper::Remapping> remapping = ImportRemapper::parseRemapping(positionalArg);
|
optional<ImportRemapper::Remapping> remapping = ImportRemapper::parseRemapping(positionalArg);
|
||||||
if (!remapping.has_value())
|
if (!remapping.has_value())
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid remapping: \"" + positionalArg + "\".");
|
||||||
serr() << "Invalid remapping: \"" << positionalArg << "\"." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_options.input.mode == InputMode::StandardJson)
|
if (m_options.input.mode == InputMode::StandardJson)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Import remappings are not accepted on the command line in Standard JSON mode." << endl;
|
CommandLineValidationError,
|
||||||
serr() << "Please put them under 'settings.remappings' in the JSON input." << endl;
|
"Import remappings are not accepted on the command line in Standard JSON mode.\n"
|
||||||
return false;
|
"Please put them under 'settings.remappings' in the JSON input."
|
||||||
}
|
);
|
||||||
|
|
||||||
m_options.input.remappings.emplace_back(move(remapping.value()));
|
m_options.input.remappings.emplace_back(move(remapping.value()));
|
||||||
}
|
}
|
||||||
@ -312,26 +305,24 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
|||||||
if (m_options.input.mode == InputMode::StandardJson)
|
if (m_options.input.mode == InputMode::StandardJson)
|
||||||
{
|
{
|
||||||
if (m_options.input.paths.size() > 1 || (m_options.input.paths.size() == 1 && m_options.input.addStdin))
|
if (m_options.input.paths.size() > 1 || (m_options.input.paths.size() == 1 && m_options.input.addStdin))
|
||||||
{
|
solThrow(
|
||||||
serr() << "Too many input files for --" << g_strStandardJSON << "." << endl;
|
CommandLineValidationError,
|
||||||
serr() << "Please either specify a single file name or provide its content on standard input." << endl;
|
"Too many input files for --" + g_strStandardJSON + ".\n"
|
||||||
return false;
|
"Please either specify a single file name or provide its content on standard input."
|
||||||
}
|
);
|
||||||
else if (m_options.input.paths.size() == 0)
|
else if (m_options.input.paths.size() == 0)
|
||||||
// Standard JSON mode input used to be handled separately and zero files meant "read from stdin".
|
// Standard JSON mode input used to be handled separately and zero files meant "read from stdin".
|
||||||
// Keep it working that way for backwards-compatibility.
|
// Keep it working that way for backwards-compatibility.
|
||||||
m_options.input.addStdin = true;
|
m_options.input.addStdin = true;
|
||||||
}
|
}
|
||||||
else if (m_options.input.paths.size() == 0 && !m_options.input.addStdin)
|
else if (m_options.input.paths.size() == 0 && !m_options.input.addStdin)
|
||||||
{
|
solThrow(
|
||||||
serr() << "No input files given. If you wish to use the standard input please specify \"-\" explicitly." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"No input files given. If you wish to use the standard input please specify \"-\" explicitly."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
void CommandLineParser::parseLibraryOption(string const& _input)
|
||||||
}
|
|
||||||
|
|
||||||
bool CommandLineParser::parseLibraryOption(string const& _input)
|
|
||||||
{
|
{
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
string data = _input;
|
string data = _input;
|
||||||
@ -366,71 +357,71 @@ bool CommandLineParser::parseLibraryOption(string const& _input)
|
|||||||
{
|
{
|
||||||
separator = lib.rfind(':');
|
separator = lib.rfind(':');
|
||||||
if (separator == string::npos)
|
if (separator == string::npos)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Equal sign separator missing in library address specifier \"" << lib << "\"" << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Equal sign separator missing in library address specifier \"" + lib + "\""
|
||||||
}
|
);
|
||||||
else
|
else
|
||||||
isSeparatorEqualSign = false; // separator is colon
|
isSeparatorEqualSign = false; // separator is colon
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (lib.rfind('=') != lib.find('='))
|
if (lib.rfind('=') != lib.find('='))
|
||||||
{
|
solThrow(
|
||||||
serr() << "Only one equal sign \"=\" is allowed in the address string \"" << lib << "\"." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Only one equal sign \"=\" is allowed in the address string \"" + lib + "\"."
|
||||||
}
|
);
|
||||||
|
|
||||||
string libName(lib.begin(), lib.begin() + static_cast<ptrdiff_t>(separator));
|
string libName(lib.begin(), lib.begin() + static_cast<ptrdiff_t>(separator));
|
||||||
boost::trim(libName);
|
boost::trim(libName);
|
||||||
if (m_options.linker.libraries.count(libName))
|
if (m_options.linker.libraries.count(libName))
|
||||||
{
|
solThrow(
|
||||||
serr() << "Address specified more than once for library \"" << libName << "\"." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Address specified more than once for library \"" + libName + "\"."
|
||||||
}
|
);
|
||||||
|
|
||||||
string addrString(lib.begin() + static_cast<ptrdiff_t>(separator) + 1, lib.end());
|
string addrString(lib.begin() + static_cast<ptrdiff_t>(separator) + 1, lib.end());
|
||||||
boost::trim(addrString);
|
boost::trim(addrString);
|
||||||
if (addrString.empty())
|
if (addrString.empty())
|
||||||
{
|
solThrow(
|
||||||
serr() << "Empty address provided for library \"" << libName << "\"." << endl;
|
CommandLineValidationError,
|
||||||
serr() << "Note that there should not be any whitespace after the " << (isSeparatorEqualSign ? "equal sign" : "colon") << "." << endl;
|
"Empty address provided for library \"" + libName + "\".\n"
|
||||||
return false;
|
"Note that there should not be any whitespace after the " +
|
||||||
}
|
(isSeparatorEqualSign ? "equal sign" : "colon") + "."
|
||||||
|
);
|
||||||
|
|
||||||
if (addrString.substr(0, 2) == "0x")
|
if (addrString.substr(0, 2) == "0x")
|
||||||
addrString = addrString.substr(2);
|
addrString = addrString.substr(2);
|
||||||
else
|
else
|
||||||
{
|
solThrow(
|
||||||
serr() << "The address " << addrString << " is not prefixed with \"0x\"." << endl;
|
CommandLineValidationError,
|
||||||
serr() << "Note that the address must be prefixed with \"0x\"." << endl;
|
"The address " + addrString + " is not prefixed with \"0x\".\n"
|
||||||
return false;
|
"Note that the address must be prefixed with \"0x\"."
|
||||||
}
|
);
|
||||||
|
|
||||||
if (addrString.length() != 40)
|
if (addrString.length() != 40)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Invalid length for address for library \"" << libName << "\": " << addrString.length() << " instead of 40 characters." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Invalid length for address for library \"" + libName + "\": " +
|
||||||
}
|
to_string(addrString.length()) + " instead of 40 characters."
|
||||||
|
);
|
||||||
if (!passesAddressChecksum(addrString, false))
|
if (!passesAddressChecksum(addrString, false))
|
||||||
{
|
solThrow(
|
||||||
serr() << "Invalid checksum on address for library \"" << libName << "\": " << addrString << endl;
|
CommandLineValidationError,
|
||||||
serr() << "The correct checksum is " << getChecksummedAddress(addrString) << endl;
|
"Invalid checksum on address for library \"" + libName + "\": " + addrString + "\n"
|
||||||
return false;
|
"The correct checksum is " + getChecksummedAddress(addrString)
|
||||||
}
|
);
|
||||||
bytes binAddr = fromHex(addrString);
|
bytes binAddr = fromHex(addrString);
|
||||||
h160 address(binAddr, h160::AlignRight);
|
h160 address(binAddr, h160::AlignRight);
|
||||||
if (binAddr.size() > 20 || address == h160())
|
if (binAddr.size() > 20 || address == h160())
|
||||||
{
|
solThrow(
|
||||||
serr() << "Invalid address for library \"" << libName << "\": " << addrString << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Invalid address for library \"" + libName + "\": " + addrString
|
||||||
}
|
);
|
||||||
m_options.linker.libraries[libName] = address;
|
m_options.linker.libraries[libName] = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parseOutputSelection()
|
void CommandLineParser::parseOutputSelection()
|
||||||
{
|
{
|
||||||
static auto outputSupported = [](InputMode _mode, string_view _outputName)
|
static auto outputSupported = [](InputMode _mode, string_view _outputName)
|
||||||
{
|
{
|
||||||
@ -486,13 +477,11 @@ bool CommandLineParser::parseOutputSelection()
|
|||||||
unsupportedOutputs.push_back(optionName);
|
unsupportedOutputs.push_back(optionName);
|
||||||
|
|
||||||
if (!unsupportedOutputs.empty())
|
if (!unsupportedOutputs.empty())
|
||||||
{
|
solThrow(
|
||||||
serr() << "The following outputs are not supported in " << g_inputModeName.at(m_options.input.mode) << " mode: ";
|
CommandLineValidationError,
|
||||||
serr() << joinOptionNames(unsupportedOutputs) << ".";
|
"The following outputs are not supported in " + g_inputModeName.at(m_options.input.mode) + " mode: " +
|
||||||
return false;
|
joinOptionNames(unsupportedOutputs) + "."
|
||||||
}
|
);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
po::options_description CommandLineParser::optionsDescription()
|
po::options_description CommandLineParser::optionsDescription()
|
||||||
@ -831,7 +820,7 @@ po::positional_options_description CommandLineParser::positionalOptionsDescripti
|
|||||||
return filesPositions;
|
return filesPositions;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parseArgs(int _argc, char const* const* _argv)
|
void CommandLineParser::parseArgs(int _argc, char const* const* _argv)
|
||||||
{
|
{
|
||||||
po::options_description allOptions = optionsDescription();
|
po::options_description allOptions = optionsDescription();
|
||||||
po::positional_options_description filesPositions = positionalOptionsDescription();
|
po::positional_options_description filesPositions = positionalOptionsDescription();
|
||||||
@ -846,18 +835,15 @@ bool CommandLineParser::parseArgs(int _argc, char const* const* _argv)
|
|||||||
}
|
}
|
||||||
catch (po::error const& _exception)
|
catch (po::error const& _exception)
|
||||||
{
|
{
|
||||||
serr() << _exception.what() << endl;
|
solThrow(CommandLineValidationError, _exception.what());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
po::notify(m_args);
|
po::notify(m_args);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::processArgs()
|
void CommandLineParser::processArgs()
|
||||||
{
|
{
|
||||||
if (!checkMutuallyExclusive({
|
checkMutuallyExclusive({
|
||||||
g_strHelp,
|
g_strHelp,
|
||||||
g_strLicense,
|
g_strLicense,
|
||||||
g_strVersion,
|
g_strVersion,
|
||||||
@ -867,8 +853,7 @@ bool CommandLineParser::processArgs()
|
|||||||
g_strStrictAssembly,
|
g_strStrictAssembly,
|
||||||
g_strYul,
|
g_strYul,
|
||||||
g_strImportAst,
|
g_strImportAst,
|
||||||
}))
|
});
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_args.count(g_strHelp) > 0)
|
if (m_args.count(g_strHelp) > 0)
|
||||||
m_options.input.mode = InputMode::Help;
|
m_options.input.mode = InputMode::Help;
|
||||||
@ -892,7 +877,7 @@ bool CommandLineParser::processArgs()
|
|||||||
m_options.input.mode == InputMode::License ||
|
m_options.input.mode == InputMode::License ||
|
||||||
m_options.input.mode == InputMode::Version
|
m_options.input.mode == InputMode::Version
|
||||||
)
|
)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
map<string, set<InputMode>> validOptionInputModeCombinations = {
|
map<string, set<InputMode>> validOptionInputModeCombinations = {
|
||||||
// TODO: This should eventually contain all options.
|
// TODO: This should eventually contain all options.
|
||||||
@ -907,13 +892,13 @@ bool CommandLineParser::processArgs()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!invalidOptionsForCurrentInputMode.empty())
|
if (!invalidOptionsForCurrentInputMode.empty())
|
||||||
{
|
solThrow(
|
||||||
serr() << "The following options are not supported in the current input mode: " << joinOptionNames(invalidOptionsForCurrentInputMode) << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"The following options are not supported in the current input mode: " +
|
||||||
}
|
joinOptionNames(invalidOptionsForCurrentInputMode)
|
||||||
|
);
|
||||||
|
|
||||||
if (!checkMutuallyExclusive({g_strColor, g_strNoColor}))
|
checkMutuallyExclusive({g_strColor, g_strNoColor});
|
||||||
return false;
|
|
||||||
|
|
||||||
array<string, 9> const conflictingWithStopAfter{
|
array<string, 9> const conflictingWithStopAfter{
|
||||||
CompilerOutputs::componentName(&CompilerOutputs::binary),
|
CompilerOutputs::componentName(&CompilerOutputs::binary),
|
||||||
@ -928,8 +913,7 @@ bool CommandLineParser::processArgs()
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (auto& option: conflictingWithStopAfter)
|
for (auto& option: conflictingWithStopAfter)
|
||||||
if (!checkMutuallyExclusive({g_strStopAfter, option}))
|
checkMutuallyExclusive({g_strStopAfter, option});
|
||||||
return false;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
m_options.input.mode != InputMode::Compiler &&
|
m_options.input.mode != InputMode::Compiler &&
|
||||||
@ -938,23 +922,23 @@ bool CommandLineParser::processArgs()
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!m_args[g_strOptimizeRuns].defaulted())
|
if (!m_args[g_strOptimizeRuns].defaulted())
|
||||||
{
|
solThrow(
|
||||||
serr() << "Option --" << g_strOptimizeRuns << " is only valid in compiler and assembler modes." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Option --" + g_strOptimizeRuns + " is only valid in compiler and assembler modes."
|
||||||
}
|
);
|
||||||
|
|
||||||
for (string const& option: {g_strOptimize, g_strNoOptimizeYul, g_strOptimizeYul, g_strYulOptimizations})
|
for (string const& option: {g_strOptimize, g_strNoOptimizeYul, g_strOptimizeYul, g_strYulOptimizations})
|
||||||
if (m_args.count(option) > 0)
|
if (m_args.count(option) > 0)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Option --" << option << " is only valid in compiler and assembler modes." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Option --" + option + " is only valid in compiler and assembler modes."
|
||||||
}
|
);
|
||||||
|
|
||||||
if (!m_args[g_strDebugInfo].defaulted())
|
if (!m_args[g_strDebugInfo].defaulted())
|
||||||
{
|
solThrow(
|
||||||
serr() << "Option --" << g_strDebugInfo << " is only valid in compiler and assembler modes." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Option --" + g_strDebugInfo + " is only valid in compiler and assembler modes."
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_args.count(g_strColor) > 0)
|
if (m_args.count(g_strColor) > 0)
|
||||||
@ -969,15 +953,15 @@ bool CommandLineParser::processArgs()
|
|||||||
string revertStringsString = m_args[g_strRevertStrings].as<string>();
|
string revertStringsString = m_args[g_strRevertStrings].as<string>();
|
||||||
std::optional<RevertStrings> revertStrings = revertStringsFromString(revertStringsString);
|
std::optional<RevertStrings> revertStrings = revertStringsFromString(revertStringsString);
|
||||||
if (!revertStrings)
|
if (!revertStrings)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Invalid option for --" << g_strRevertStrings << ": " << revertStringsString << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Invalid option for --" + g_strRevertStrings + ": " + revertStringsString
|
||||||
}
|
);
|
||||||
if (*revertStrings == RevertStrings::VerboseDebug)
|
if (*revertStrings == RevertStrings::VerboseDebug)
|
||||||
{
|
solThrow(
|
||||||
serr() << "Only \"default\", \"strip\" and \"debug\" are implemented for --" << g_strRevertStrings << " for now." << endl;
|
CommandLineValidationError,
|
||||||
return false;
|
"Only \"default\", \"strip\" and \"debug\" are implemented for --" + g_strRevertStrings + " for now."
|
||||||
}
|
);
|
||||||
m_options.output.revertStrings = *revertStrings;
|
m_options.output.revertStrings = *revertStrings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -986,20 +970,13 @@ bool CommandLineParser::processArgs()
|
|||||||
string optionValue = m_args[g_strDebugInfo].as<string>();
|
string optionValue = m_args[g_strDebugInfo].as<string>();
|
||||||
m_options.output.debugInfoSelection = DebugInfoSelection::fromString(optionValue);
|
m_options.output.debugInfoSelection = DebugInfoSelection::fromString(optionValue);
|
||||||
if (!m_options.output.debugInfoSelection.has_value())
|
if (!m_options.output.debugInfoSelection.has_value())
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid value for --" + g_strDebugInfo + " option: " + optionValue);
|
||||||
serr() << "Invalid value for --" << g_strDebugInfo << " option: " << optionValue << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_options.output.debugInfoSelection->snippet && !m_options.output.debugInfoSelection->location)
|
if (m_options.output.debugInfoSelection->snippet && !m_options.output.debugInfoSelection->location)
|
||||||
{
|
solThrow(CommandLineValidationError, "To use 'snippet' with --" + g_strDebugInfo + " you must select also 'location'.");
|
||||||
serr() << "To use 'snippet' with --" << g_strDebugInfo << " you must select also 'location'." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseCombinedJsonOption())
|
parseCombinedJsonOption();
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_args.count(g_strOutputDir))
|
if (m_args.count(g_strOutputDir))
|
||||||
m_options.output.dir = m_args.at(g_strOutputDir).as<string>();
|
m_options.output.dir = m_args.at(g_strOutputDir).as<string>();
|
||||||
@ -1016,8 +993,7 @@ bool CommandLineParser::processArgs()
|
|||||||
m_options.formatting.json.indent = m_args[g_strJsonIndent].as<uint32_t>();
|
m_options.formatting.json.indent = m_args[g_strJsonIndent].as<uint32_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseOutputSelection())
|
parseOutputSelection();
|
||||||
return false;
|
|
||||||
|
|
||||||
m_options.compiler.estimateGas = (m_args.count(g_strGas) > 0);
|
m_options.compiler.estimateGas = (m_args.count(g_strGas) > 0);
|
||||||
|
|
||||||
@ -1027,18 +1003,13 @@ bool CommandLineParser::processArgs()
|
|||||||
if (m_args.count(g_strIncludePath) > 0)
|
if (m_args.count(g_strIncludePath) > 0)
|
||||||
{
|
{
|
||||||
if (m_options.input.basePath.empty())
|
if (m_options.input.basePath.empty())
|
||||||
{
|
solThrow(CommandLineValidationError, "--" + g_strIncludePath + " option requires a non-empty base path.");
|
||||||
serr() << "--" << g_strIncludePath << " option requires a non-empty base path." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (string const& includePath: m_args[g_strIncludePath].as<vector<string>>())
|
for (string const& includePath: m_args[g_strIncludePath].as<vector<string>>())
|
||||||
{
|
{
|
||||||
if (includePath.empty())
|
if (includePath.empty())
|
||||||
{
|
solThrow(CommandLineValidationError, "Empty values are not allowed in --" + g_strIncludePath + ".");
|
||||||
serr() << "Empty values are not allowed in --" << g_strIncludePath << "." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.input.includePaths.push_back(includePath);
|
m_options.input.includePaths.push_back(includePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1054,37 +1025,29 @@ bool CommandLineParser::processArgs()
|
|||||||
if (m_args.count(g_strStopAfter))
|
if (m_args.count(g_strStopAfter))
|
||||||
{
|
{
|
||||||
if (m_args[g_strStopAfter].as<string>() != "parsing")
|
if (m_args[g_strStopAfter].as<string>() != "parsing")
|
||||||
{
|
solThrow(CommandLineValidationError, "Valid options for --" + g_strStopAfter + " are: \"parsing\".\n");
|
||||||
serr() << "Valid options for --" << g_strStopAfter << " are: \"parsing\".\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
m_options.output.stopAfter = CompilerStack::State::Parsed;
|
m_options.output.stopAfter = CompilerStack::State::Parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseInputPathsAndRemappings())
|
parseInputPathsAndRemappings();
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_options.input.mode == InputMode::StandardJson)
|
if (m_options.input.mode == InputMode::StandardJson)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
if (m_args.count(g_strLibraries))
|
if (m_args.count(g_strLibraries))
|
||||||
for (string const& library: m_args[g_strLibraries].as<vector<string>>())
|
for (string const& library: m_args[g_strLibraries].as<vector<string>>())
|
||||||
if (!parseLibraryOption(library))
|
parseLibraryOption(library);
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_options.input.mode == InputMode::Linker)
|
if (m_options.input.mode == InputMode::Linker)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
if (m_args.count(g_strEVMVersion))
|
if (m_args.count(g_strEVMVersion))
|
||||||
{
|
{
|
||||||
string versionOptionStr = m_args[g_strEVMVersion].as<string>();
|
string versionOptionStr = m_args[g_strEVMVersion].as<string>();
|
||||||
std::optional<langutil::EVMVersion> versionOption = langutil::EVMVersion::fromString(versionOptionStr);
|
std::optional<langutil::EVMVersion> versionOption = langutil::EVMVersion::fromString(versionOptionStr);
|
||||||
if (!versionOption)
|
if (!versionOption)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strEVMVersion + ": " + versionOptionStr);
|
||||||
serr() << "Invalid option for --" << g_strEVMVersion << ": " << versionOptionStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.output.evmVersion = *versionOption;
|
m_options.output.evmVersion = *versionOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1097,10 +1060,7 @@ bool CommandLineParser::processArgs()
|
|||||||
{
|
{
|
||||||
OptimiserSettings optimiserSettings = m_options.optimiserSettings();
|
OptimiserSettings optimiserSettings = m_options.optimiserSettings();
|
||||||
if (!optimiserSettings.runYulOptimiser)
|
if (!optimiserSettings.runYulOptimiser)
|
||||||
{
|
solThrow(CommandLineValidationError, "--" + g_strYulOptimizations + " is invalid if Yul optimizer is disabled");
|
||||||
serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1108,8 +1068,10 @@ bool CommandLineParser::processArgs()
|
|||||||
}
|
}
|
||||||
catch (yul::OptimizerException const& _exception)
|
catch (yul::OptimizerException const& _exception)
|
||||||
{
|
{
|
||||||
serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl;
|
solThrow(
|
||||||
return false;
|
CommandLineValidationError,
|
||||||
|
"Invalid optimizer step sequence in --" + g_strYulOptimizations + ": " + _exception.what()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as<string>();
|
m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as<string>();
|
||||||
@ -1130,12 +1092,11 @@ bool CommandLineParser::processArgs()
|
|||||||
auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; };
|
auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; };
|
||||||
auto enabledOptions = nonAssemblyModeOptions | ranges::views::filter(optionEnabled) | ranges::to_vector;
|
auto enabledOptions = nonAssemblyModeOptions | ranges::views::filter(optionEnabled) | ranges::to_vector;
|
||||||
|
|
||||||
serr() << "The following options are invalid in assembly mode: ";
|
string message = "The following options are invalid in assembly mode: " + joinOptionNames(enabledOptions) + ".";
|
||||||
serr() << joinOptionNames(enabledOptions) << ".";
|
|
||||||
if (m_args.count(g_strOptimizeYul) || m_args.count(g_strNoOptimizeYul))
|
if (m_args.count(g_strOptimizeYul) || m_args.count(g_strNoOptimizeYul))
|
||||||
serr() << " Optimization is disabled by default and can be enabled with --" << g_strOptimize << "." << endl;
|
message += " Optimization is disabled by default and can be enabled with --" + g_strOptimize + ".";
|
||||||
serr() << endl;
|
|
||||||
return false;
|
solThrow(CommandLineValidationError, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch to assembly mode
|
// switch to assembly mode
|
||||||
@ -1151,10 +1112,7 @@ bool CommandLineParser::processArgs()
|
|||||||
else if (machine == g_strEwasm)
|
else if (machine == g_strEwasm)
|
||||||
m_options.assembly.targetMachine = Machine::Ewasm;
|
m_options.assembly.targetMachine = Machine::Ewasm;
|
||||||
else
|
else
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strMachine + ": " + machine);
|
||||||
serr() << "Invalid option for --" << g_strMachine << ": " << machine << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_options.assembly.targetMachine == Machine::Ewasm && m_options.assembly.inputLanguage == Input::StrictAssembly)
|
if (m_options.assembly.targetMachine == Machine::Ewasm && m_options.assembly.inputLanguage == Input::StrictAssembly)
|
||||||
m_options.assembly.inputLanguage = Input::Ewasm;
|
m_options.assembly.inputLanguage = Input::Ewasm;
|
||||||
@ -1167,45 +1125,33 @@ bool CommandLineParser::processArgs()
|
|||||||
{
|
{
|
||||||
m_options.assembly.inputLanguage = Input::Ewasm;
|
m_options.assembly.inputLanguage = Input::Ewasm;
|
||||||
if (m_options.assembly.targetMachine != Machine::Ewasm)
|
if (m_options.assembly.targetMachine != Machine::Ewasm)
|
||||||
{
|
solThrow(
|
||||||
serr() << "If you select Ewasm as --" << g_strYulDialect << ", ";
|
CommandLineValidationError,
|
||||||
serr() << "--" << g_strMachine << " has to be Ewasm as well." << endl;
|
"If you select Ewasm as --" + g_strYulDialect + ", "
|
||||||
return false;
|
"--" + g_strMachine + " has to be Ewasm as well."
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strYulDialect + ": " + dialect);
|
||||||
serr() << "Invalid option for --" << g_strYulDialect << ": " << dialect << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_options.optimizer.enabled && (m_options.assembly.inputLanguage != Input::StrictAssembly && m_options.assembly.inputLanguage != Input::Ewasm))
|
if (m_options.optimizer.enabled && (m_options.assembly.inputLanguage != Input::StrictAssembly && m_options.assembly.inputLanguage != Input::Ewasm))
|
||||||
{
|
solThrow(
|
||||||
serr() <<
|
CommandLineValidationError,
|
||||||
"Optimizer can only be used for strict assembly. Use --" <<
|
"Optimizer can only be used for strict assembly. Use --" + g_strStrictAssembly + "."
|
||||||
g_strStrictAssembly <<
|
);
|
||||||
"." <<
|
|
||||||
endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m_options.assembly.targetMachine == Machine::Ewasm && m_options.assembly.inputLanguage != Input::StrictAssembly && m_options.assembly.inputLanguage != Input::Ewasm)
|
if (m_options.assembly.targetMachine == Machine::Ewasm && m_options.assembly.inputLanguage != Input::StrictAssembly && m_options.assembly.inputLanguage != Input::Ewasm)
|
||||||
{
|
solThrow(
|
||||||
serr() << "The selected input language is not directly supported when targeting the Ewasm machine ";
|
CommandLineValidationError,
|
||||||
serr() << "and automatic translation is not available." << endl;
|
"The selected input language is not directly supported when targeting the Ewasm machine "
|
||||||
return false;
|
"and automatic translation is not available."
|
||||||
}
|
);
|
||||||
serr() <<
|
return;
|
||||||
"Warning: Yul is still experimental. Please use the output with care." <<
|
|
||||||
endl;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else if (countEnabledOptions({g_strYulDialect, g_strMachine}) >= 1)
|
else if (countEnabledOptions({g_strYulDialect, g_strMachine}) >= 1)
|
||||||
{
|
solThrow(
|
||||||
serr() << "--" << g_strYulDialect << " and --" << g_strMachine << " ";
|
CommandLineValidationError,
|
||||||
serr() << "are only valid in assembly mode." << endl;
|
"--" + g_strYulDialect + " and --" + g_strMachine + " are only valid in assembly mode."
|
||||||
return false;
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (m_args.count(g_strMetadataHash))
|
if (m_args.count(g_strMetadataHash))
|
||||||
{
|
{
|
||||||
@ -1217,10 +1163,7 @@ bool CommandLineParser::processArgs()
|
|||||||
else if (hashStr == g_strNone)
|
else if (hashStr == g_strNone)
|
||||||
m_options.metadata.hash = CompilerStack::MetadataHash::None;
|
m_options.metadata.hash = CompilerStack::MetadataHash::None;
|
||||||
else
|
else
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strMetadataHash + ": " + hashStr);
|
||||||
serr() << "Invalid option for --" << g_strMetadataHash << ": " << hashStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_args.count(g_strModelCheckerContracts))
|
if (m_args.count(g_strModelCheckerContracts))
|
||||||
@ -1228,10 +1171,7 @@ bool CommandLineParser::processArgs()
|
|||||||
string contractsStr = m_args[g_strModelCheckerContracts].as<string>();
|
string contractsStr = m_args[g_strModelCheckerContracts].as<string>();
|
||||||
optional<ModelCheckerContracts> contracts = ModelCheckerContracts::fromString(contractsStr);
|
optional<ModelCheckerContracts> contracts = ModelCheckerContracts::fromString(contractsStr);
|
||||||
if (!contracts)
|
if (!contracts)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strModelCheckerContracts + ": " + contractsStr);
|
||||||
serr() << "Invalid option for --" << g_strModelCheckerContracts << ": " << contractsStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.modelChecker.settings.contracts = move(*contracts);
|
m_options.modelChecker.settings.contracts = move(*contracts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,10 +1183,7 @@ bool CommandLineParser::processArgs()
|
|||||||
string engineStr = m_args[g_strModelCheckerEngine].as<string>();
|
string engineStr = m_args[g_strModelCheckerEngine].as<string>();
|
||||||
optional<ModelCheckerEngine> engine = ModelCheckerEngine::fromString(engineStr);
|
optional<ModelCheckerEngine> engine = ModelCheckerEngine::fromString(engineStr);
|
||||||
if (!engine)
|
if (!engine)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strModelCheckerEngine + ": " + engineStr);
|
||||||
serr() << "Invalid option for --" << g_strModelCheckerEngine << ": " << engineStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.modelChecker.settings.engine = *engine;
|
m_options.modelChecker.settings.engine = *engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,10 +1192,7 @@ bool CommandLineParser::processArgs()
|
|||||||
string invsStr = m_args[g_strModelCheckerInvariants].as<string>();
|
string invsStr = m_args[g_strModelCheckerInvariants].as<string>();
|
||||||
optional<ModelCheckerInvariants> invs = ModelCheckerInvariants::fromString(invsStr);
|
optional<ModelCheckerInvariants> invs = ModelCheckerInvariants::fromString(invsStr);
|
||||||
if (!invs)
|
if (!invs)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strModelCheckerInvariants + ": " + invsStr);
|
||||||
serr() << "Invalid option for --" << g_strModelCheckerInvariants << ": " << invsStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.modelChecker.settings.invariants = *invs;
|
m_options.modelChecker.settings.invariants = *invs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1270,10 +1204,7 @@ bool CommandLineParser::processArgs()
|
|||||||
string solversStr = m_args[g_strModelCheckerSolvers].as<string>();
|
string solversStr = m_args[g_strModelCheckerSolvers].as<string>();
|
||||||
optional<smtutil::SMTSolverChoice> solvers = smtutil::SMTSolverChoice::fromString(solversStr);
|
optional<smtutil::SMTSolverChoice> solvers = smtutil::SMTSolverChoice::fromString(solversStr);
|
||||||
if (!solvers)
|
if (!solvers)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strModelCheckerSolvers + ": " + solversStr);
|
||||||
serr() << "Invalid option for --" << g_strModelCheckerSolvers << ": " << solversStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.modelChecker.settings.solvers = *solvers;
|
m_options.modelChecker.settings.solvers = *solvers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,10 +1213,7 @@ bool CommandLineParser::processArgs()
|
|||||||
string targetsStr = m_args[g_strModelCheckerTargets].as<string>();
|
string targetsStr = m_args[g_strModelCheckerTargets].as<string>();
|
||||||
optional<ModelCheckerTargets> targets = ModelCheckerTargets::fromString(targetsStr);
|
optional<ModelCheckerTargets> targets = ModelCheckerTargets::fromString(targetsStr);
|
||||||
if (!targets)
|
if (!targets)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option for --" + g_strModelCheckerTargets + ": " + targetsStr);
|
||||||
serr() << "Invalid option for --" << g_strModelCheckerTargets << ": " << targetsStr << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_options.modelChecker.settings.targets = *targets;
|
m_options.modelChecker.settings.targets = *targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1307,27 +1235,21 @@ bool CommandLineParser::processArgs()
|
|||||||
m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0);
|
m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0);
|
||||||
|
|
||||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport);
|
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandLineParser::parseCombinedJsonOption()
|
void CommandLineParser::parseCombinedJsonOption()
|
||||||
{
|
{
|
||||||
if (!m_args.count(g_strCombinedJson))
|
if (!m_args.count(g_strCombinedJson))
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
set<string> requests;
|
set<string> requests;
|
||||||
for (string const& item: boost::split(requests, m_args[g_strCombinedJson].as<string>(), boost::is_any_of(",")))
|
for (string const& item: boost::split(requests, m_args[g_strCombinedJson].as<string>(), boost::is_any_of(",")))
|
||||||
if (CombinedJsonRequests::componentMap().count(item) == 0)
|
if (CombinedJsonRequests::componentMap().count(item) == 0)
|
||||||
{
|
solThrow(CommandLineValidationError, "Invalid option to --" + g_strCombinedJson + ": " + item);
|
||||||
serr() << "Invalid option to --" << g_strCombinedJson << ": " << item << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_options.compiler.combinedJsonRequests = CombinedJsonRequests{};
|
m_options.compiler.combinedJsonRequests = CombinedJsonRequests{};
|
||||||
for (auto&& [componentName, component]: CombinedJsonRequests::componentMap())
|
for (auto&& [componentName, component]: CombinedJsonRequests::componentMap())
|
||||||
m_options.compiler.combinedJsonRequests.value().*component = (requests.count(componentName) > 0);
|
m_options.compiler.combinedJsonRequests.value().*component = (requests.count(componentName) > 0);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CommandLineParser::countEnabledOptions(vector<string> const& _optionNames) const
|
size_t CommandLineParser::countEnabledOptions(vector<string> const& _optionNames) const
|
||||||
|
@ -234,27 +234,17 @@ struct CommandLineOptions
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Parses the command-line arguments and produces a filled-out CommandLineOptions structure.
|
/// Parses the command-line arguments and produces a filled-out CommandLineOptions structure.
|
||||||
/// Validates provided values and prints error messages in case of errors.
|
/// Validates provided values and reports errors by throwing @p CommandLineValidationErrors.
|
||||||
class CommandLineParser
|
class CommandLineParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CommandLineParser(std::ostream& _serr):
|
|
||||||
m_serr(_serr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// Parses the command-line arguments and fills out the internal CommandLineOptions structure.
|
/// Parses the command-line arguments and fills out the internal CommandLineOptions structure.
|
||||||
/// Performs validation and prints error messages.
|
/// @throws CommandLineValidationError if the arguments cannot be properly parsed or are invalid.
|
||||||
/// @return true if there were no validation errors when parsing options and the
|
/// When an exception is thrown, the @p CommandLineOptions may be only partially filled out.
|
||||||
/// CommandLineOptions structure has been fully initialized. false if there were errors - in
|
void parse(int _argc, char const* const* _argv);
|
||||||
/// this case CommandLineOptions may be only partially filled out. May also return false if
|
|
||||||
/// there is not further processing necessary and the program should just exit.
|
|
||||||
bool parse(int _argc, char const* const* _argv);
|
|
||||||
|
|
||||||
CommandLineOptions const& options() const { return m_options; }
|
CommandLineOptions const& options() const { return m_options; }
|
||||||
|
|
||||||
/// Returns true if the parser has written anything to any of its output streams.
|
|
||||||
bool hasOutput() const { return m_hasOutput; }
|
|
||||||
|
|
||||||
static void printHelp(std::ostream& _out) { _out << optionsDescription(); }
|
static void printHelp(std::ostream& _out) { _out << optionsDescription(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -269,40 +259,32 @@ private:
|
|||||||
/// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args.
|
/// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args.
|
||||||
/// Also handles the arguments that result in information being printed followed by immediate exit.
|
/// Also handles the arguments that result in information being printed followed by immediate exit.
|
||||||
/// @returns false if parsing fails due to syntactical errors or the arguments not matching the description.
|
/// @returns false if parsing fails due to syntactical errors or the arguments not matching the description.
|
||||||
bool parseArgs(int _argc, char const* const* _argv);
|
void parseArgs(int _argc, char const* const* _argv);
|
||||||
|
|
||||||
/// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions
|
/// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions
|
||||||
/// structure.
|
/// structure.
|
||||||
/// @return false if there are any validation errors, true otherwise.
|
/// @throws CommandLineValidationError in case of validation errors.
|
||||||
bool processArgs();
|
void processArgs();
|
||||||
|
|
||||||
/// Parses the value supplied to --combined-json.
|
/// Parses the value supplied to --combined-json.
|
||||||
/// @return false if there are any validation errors, true otherwise.
|
/// @throws CommandLineValidationError in case of validation errors.
|
||||||
bool parseCombinedJsonOption();
|
void parseCombinedJsonOption();
|
||||||
|
|
||||||
/// Parses the names of the input files, remappings for all modes except for Standard JSON.
|
/// Parses the names of the input files, remappings. Does not check if the files actually exist.
|
||||||
/// Does not check if files actually exist.
|
/// @throws CommandLineValidationError in case of validation errors.
|
||||||
/// @return false if there are any validation errors, true otherwise.
|
void parseInputPathsAndRemappings();
|
||||||
bool parseInputPathsAndRemappings();
|
|
||||||
|
|
||||||
/// Tries to read from the file @a _input or interprets @a _input literally if that fails.
|
/// Tries to read from the file @a _input or interprets @a _input literally if that fails.
|
||||||
/// It then tries to parse the contents and appends to m_options.libraries.
|
/// It then tries to parse the contents and appends to @a m_options.libraries.
|
||||||
/// @return false if there are any validation errors, true otherwise.
|
/// @throws CommandLineValidationError in case of validation errors.
|
||||||
bool parseLibraryOption(std::string const& _input);
|
void parseLibraryOption(std::string const& _input);
|
||||||
|
|
||||||
bool parseOutputSelection();
|
void parseOutputSelection();
|
||||||
|
|
||||||
bool checkMutuallyExclusive(std::vector<std::string> const& _optionNames);
|
void checkMutuallyExclusive(std::vector<std::string> const& _optionNames);
|
||||||
size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const;
|
size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const;
|
||||||
static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", ");
|
static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", ");
|
||||||
|
|
||||||
/// Returns the stream that should receive error output. Sets m_hasOutput to true if the
|
|
||||||
/// stream has ever been used.
|
|
||||||
std::ostream& serr();
|
|
||||||
|
|
||||||
std::ostream& m_serr;
|
|
||||||
bool m_hasOutput = false;
|
|
||||||
|
|
||||||
CommandLineOptions m_options;
|
CommandLineOptions m_options;
|
||||||
|
|
||||||
/// Map of command-line arguments produced by boost::program_options.
|
/// Map of command-line arguments produced by boost::program_options.
|
||||||
|
34
solc/Exceptions.h
Normal file
34
solc/Exceptions.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
/**
|
||||||
|
* Exceptions used by the command-line interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
|
namespace solidity::frontend
|
||||||
|
{
|
||||||
|
|
||||||
|
struct CommandLineError: virtual util::Exception {};
|
||||||
|
struct CommandLineExecutionError: virtual CommandLineError {};
|
||||||
|
struct CommandLineValidationError: virtual CommandLineError {};
|
||||||
|
struct CommandLineOutputError: virtual CommandLineError {};
|
||||||
|
|
||||||
|
}
|
@ -62,12 +62,7 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
setDefaultOrCLocale();
|
setDefaultOrCLocale();
|
||||||
solidity::frontend::CommandLineInterface cli(cin, cout, cerr);
|
solidity::frontend::CommandLineInterface cli(cin, cout, cerr);
|
||||||
bool success =
|
return cli.run(argc, argv) ? 0 : 1;
|
||||||
cli.parseArguments(argc, argv) &&
|
|
||||||
cli.readInputFiles() &&
|
|
||||||
cli.processInput();
|
|
||||||
|
|
||||||
return success ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
catch (smtutil::SMTLogicError const& _exception)
|
catch (smtutil::SMTLogicError const& _exception)
|
||||||
{
|
{
|
||||||
|
@ -182,7 +182,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
|
|||||||
message.kind = EVMC_CALL;
|
message.kind = EVMC_CALL;
|
||||||
message.destination = EVMHost::convertToEVMC(m_contractAddress);
|
message.destination = EVMHost::convertToEVMC(m_contractAddress);
|
||||||
}
|
}
|
||||||
message.gas = m_gas.convert_to<int64_t>();
|
message.gas = InitialGas.convert_to<int64_t>();
|
||||||
|
|
||||||
evmc::result result = m_evmcHost->call(message);
|
evmc::result result = m_evmcHost->call(message);
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
|
|||||||
if (_isCreation)
|
if (_isCreation)
|
||||||
m_contractAddress = EVMHost::convertFromEVMC(result.create_address);
|
m_contractAddress = EVMHost::convertFromEVMC(result.create_address);
|
||||||
|
|
||||||
m_gasUsed = m_gas - result.gas_left;
|
m_gasUsed = InitialGas - result.gas_left;
|
||||||
m_transactionSuccessful = (result.status_code == EVMC_SUCCESS);
|
m_transactionSuccessful = (result.status_code == EVMC_SUCCESS);
|
||||||
|
|
||||||
if (m_showMessages)
|
if (m_showMessages)
|
||||||
@ -216,7 +216,7 @@ void ExecutionFramework::sendEther(h160 const& _addr, u256 const& _amount)
|
|||||||
message.value = EVMHost::convertToEVMC(_amount);
|
message.value = EVMHost::convertToEVMC(_amount);
|
||||||
message.kind = EVMC_CALL;
|
message.kind = EVMC_CALL;
|
||||||
message.destination = EVMHost::convertToEVMC(_addr);
|
message.destination = EVMHost::convertToEVMC(_addr);
|
||||||
message.gas = m_gas.convert_to<int64_t>();
|
message.gas = InitialGas.convert_to<int64_t>();
|
||||||
|
|
||||||
m_evmcHost->call(message);
|
m_evmcHost->call(message);
|
||||||
}
|
}
|
||||||
|
@ -273,6 +273,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
u256 const GasPrice = 10 * gwei;
|
||||||
|
u256 const InitialGas = 100000000;
|
||||||
|
|
||||||
void selectVM(evmc_capabilities _cap = evmc_capabilities::EVMC_CAPABILITY_EVM1);
|
void selectVM(evmc_capabilities _cap = evmc_capabilities::EVMC_CAPABILITY_EVM1);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
@ -302,8 +305,6 @@ protected:
|
|||||||
bool m_transactionSuccessful = true;
|
bool m_transactionSuccessful = true;
|
||||||
util::h160 m_sender = account(0);
|
util::h160 m_sender = account(0);
|
||||||
util::h160 m_contractAddress;
|
util::h160 m_contractAddress;
|
||||||
u256 const m_gasPrice = 10 * gwei;
|
|
||||||
u256 const m_gas = 100000000;
|
|
||||||
bytes m_output;
|
bytes m_output;
|
||||||
u256 m_gasUsed;
|
u256 m_gasUsed;
|
||||||
};
|
};
|
||||||
|
@ -54,7 +54,7 @@ do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
matching_tests=$(find . -mindepth 1 -maxdepth 1 -type d -name "$1" | cut --characters 3- | sort)
|
matching_tests=$(find . -mindepth 1 -maxdepth 1 -type d -name "$1" | cut -c 3- | sort)
|
||||||
|
|
||||||
if [[ $matching_tests == "" ]]
|
if [[ $matching_tests == "" ]]
|
||||||
then
|
then
|
||||||
@ -308,6 +308,61 @@ function test_solc_assembly_output
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_via_ir_equivalence()
|
||||||
|
{
|
||||||
|
(( $# <= 2 )) || fail "This function accepts at most two arguments."
|
||||||
|
|
||||||
|
if [[ $2 != --optimize ]] && [[ $2 != "" ]]
|
||||||
|
then
|
||||||
|
fail "The second argument must be --optimize if present."
|
||||||
|
fi
|
||||||
|
|
||||||
|
local solidity_code="$1"
|
||||||
|
local optimize_flag="$2"
|
||||||
|
|
||||||
|
local optimizer_flags=()
|
||||||
|
[[ $optimize_flag == "" ]] || optimizer_flags+=("$optimize_flag")
|
||||||
|
|
||||||
|
local ir_output
|
||||||
|
ir_output=$(
|
||||||
|
echo "$solidity_code" |
|
||||||
|
msg_on_error --no-stderr "$SOLC" - --ir-optimized --debug-info location "${optimizer_flags[@]}" |
|
||||||
|
sed '/^Optimized IR:$/d'
|
||||||
|
)
|
||||||
|
|
||||||
|
local asm_output_two_stage asm_output_via_ir
|
||||||
|
asm_output_two_stage=$(
|
||||||
|
echo "$ir_output" |
|
||||||
|
msg_on_error --no-stderr "$SOLC" - --strict-assembly --asm "${optimizer_flags[@]}" |
|
||||||
|
sed '/^======= <stdin>/d' |
|
||||||
|
sed '/^Text representation:$/d'
|
||||||
|
)
|
||||||
|
asm_output_via_ir=$(
|
||||||
|
echo "$solidity_code" |
|
||||||
|
msg_on_error --no-stderr "$SOLC" - --experimental-via-ir --asm --debug-info location "${optimizer_flags[@]}" |
|
||||||
|
sed '/^======= <stdin>/d' |
|
||||||
|
sed '/^EVM assembly:$/d'
|
||||||
|
)
|
||||||
|
|
||||||
|
diff_values "$asm_output_two_stage" "$asm_output_via_ir" --ignore-space-change --ignore-blank-lines
|
||||||
|
|
||||||
|
local bin_output_two_stage bin_output_via_ir
|
||||||
|
bin_output_two_stage=$(
|
||||||
|
echo "$ir_output" |
|
||||||
|
msg_on_error --no-stderr "$SOLC" - --strict-assembly --bin "${optimizer_flags[@]}" |
|
||||||
|
sed '/^======= <stdin>/d' |
|
||||||
|
sed '/^Binary representation:$/d'
|
||||||
|
)
|
||||||
|
bin_output_via_ir=$(
|
||||||
|
echo "$solidity_code" |
|
||||||
|
msg_on_error --no-stderr "$SOLC" - --experimental-via-ir --bin "${optimizer_flags[@]}" |
|
||||||
|
sed '/^======= <stdin>/d' |
|
||||||
|
sed '/^Binary:$/d'
|
||||||
|
)
|
||||||
|
|
||||||
|
diff_values "$bin_output_two_stage" "$bin_output_via_ir" --ignore-space-change --ignore-blank-lines
|
||||||
|
}
|
||||||
|
|
||||||
## RUN
|
## RUN
|
||||||
|
|
||||||
echo "Checking that the bug list is up to date..."
|
echo "Checking that the bug list is up to date..."
|
||||||
@ -533,6 +588,36 @@ printTask "Testing assemble, yul, strict-assembly and optimize..."
|
|||||||
test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize"
|
test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
printTask "Testing the eqivalence of --experimental-via-ir and a two-stage compilation..."
|
||||||
|
(
|
||||||
|
printTask " - Smoke test"
|
||||||
|
test_via_ir_equivalence "contract C {}"
|
||||||
|
|
||||||
|
printTask " - Smoke test (optimized)"
|
||||||
|
test_via_ir_equivalence "contract C {}" --optimize
|
||||||
|
|
||||||
|
externalContracts=(
|
||||||
|
deposit_contract.sol
|
||||||
|
FixedFeeRegistrar.sol
|
||||||
|
_stringutils/stringutils.sol
|
||||||
|
)
|
||||||
|
requiresOptimizer=(
|
||||||
|
deposit_contract.sol
|
||||||
|
FixedFeeRegistrar.sol
|
||||||
|
)
|
||||||
|
|
||||||
|
for contractFile in "${externalContracts[@]}"
|
||||||
|
do
|
||||||
|
if ! [[ "${requiresOptimizer[*]}" =~ $contractFile ]]
|
||||||
|
then
|
||||||
|
printTask " - ${contractFile}"
|
||||||
|
test_via_ir_equivalence "$(cat "${REPO_ROOT}/test/libsolidity/semanticTests/externalContracts/${contractFile}")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printTask " - ${contractFile} (optimized)"
|
||||||
|
test_via_ir_equivalence "$(cat "${REPO_ROOT}/test/libsolidity/semanticTests/externalContracts/${contractFile}")" --optimize
|
||||||
|
done
|
||||||
|
)
|
||||||
|
|
||||||
printTask "Testing standard input..."
|
printTask "Testing standard input..."
|
||||||
SOLTMPDIR=$(mktemp -d)
|
SOLTMPDIR=$(mktemp -d)
|
||||||
|
1
test/cmdlineTests/yul_to_wasm_source_location_crash/args
Normal file
1
test/cmdlineTests/yul_to_wasm_source_location_crash/args
Normal file
@ -0,0 +1 @@
|
|||||||
|
--strict-assembly --yul-dialect evm --machine ewasm --optimize --ewasm-ir
|
1
test/cmdlineTests/yul_to_wasm_source_location_crash/err
Normal file
1
test/cmdlineTests/yul_to_wasm_source_location_crash/err
Normal file
@ -0,0 +1 @@
|
|||||||
|
Warning: Yul is still experimental. Please use the output with care.
|
@ -0,0 +1,4 @@
|
|||||||
|
/// @use-src 0:"test.sol"
|
||||||
|
object "C" {
|
||||||
|
code { sstore(0,0) }
|
||||||
|
}
|
34
test/cmdlineTests/yul_to_wasm_source_location_crash/output
Normal file
34
test/cmdlineTests/yul_to_wasm_source_location_crash/output
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
======= yul_to_wasm_source_location_crash/input.yul (Ewasm) =======
|
||||||
|
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Translated source:
|
||||||
|
/// @use-src 0:"test.sol"
|
||||||
|
object "C" {
|
||||||
|
code {
|
||||||
|
function main()
|
||||||
|
{
|
||||||
|
let hi := i64.shl(i64.extend_i32_u(bswap32(i32.wrap_i64(0))), 32)
|
||||||
|
let y := i64.or(hi, i64.extend_i32_u(bswap32(i32.wrap_i64(i64.shr_u(0, 32)))))
|
||||||
|
i64.store(0:i32, y)
|
||||||
|
i64.store(i32.add(0:i32, 8:i32), y)
|
||||||
|
i64.store(i32.add(0:i32, 16:i32), y)
|
||||||
|
i64.store(i32.add(0:i32, 24:i32), y)
|
||||||
|
i64.store(32:i32, y)
|
||||||
|
i64.store(i32.add(32:i32, 8:i32), y)
|
||||||
|
i64.store(i32.add(32:i32, 16:i32), y)
|
||||||
|
i64.store(i32.add(32:i32, 24:i32), y)
|
||||||
|
eth.storageStore(0:i32, 32:i32)
|
||||||
|
}
|
||||||
|
function bswap16(x:i32) -> y:i32
|
||||||
|
{
|
||||||
|
y := i32.or(i32.and(i32.shl(x, 8:i32), 0xff00:i32), i32.and(i32.shr_u(x, 8:i32), 0xff:i32))
|
||||||
|
}
|
||||||
|
function bswap32(x:i32) -> y:i32
|
||||||
|
{
|
||||||
|
let hi:i32 := i32.shl(bswap16(x), 16:i32)
|
||||||
|
y := i32.or(hi, bswap16(i32.shr_u(x, 16:i32)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,25 +28,17 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ ! -f "$1" ]
|
|
||||||
then
|
|
||||||
echo "Usage: $0 <path to soljson.js>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SOLJSON="$1"
|
|
||||||
REPO_ROOT="$(dirname "$0")"
|
REPO_ROOT="$(dirname "$0")"
|
||||||
|
|
||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
|
verify_input "$@"
|
||||||
|
|
||||||
printTask "Running external tests..."
|
printTask "Running external tests..."
|
||||||
|
|
||||||
"$REPO_ROOT/externalTests/zeppelin.sh" "$SOLJSON"
|
"$REPO_ROOT/externalTests/zeppelin.sh" "$@"
|
||||||
"$REPO_ROOT/externalTests/gnosis.sh" "$SOLJSON"
|
"$REPO_ROOT/externalTests/gnosis.sh" "$@"
|
||||||
"$REPO_ROOT/externalTests/gnosis-v2.sh" "$SOLJSON"
|
"$REPO_ROOT/externalTests/gnosis-v2.sh" "$@"
|
||||||
"$REPO_ROOT/externalTests/colony.sh" "$SOLJSON"
|
"$REPO_ROOT/externalTests/colony.sh" "$@"
|
||||||
"$REPO_ROOT/externalTests/ens.sh" "$SOLJSON"
|
"$REPO_ROOT/externalTests/ens.sh" "$@"
|
||||||
|
|
||||||
# Disabled temporarily as it needs to be updated to latest Truffle first.
|
|
||||||
#test_truffle Gnosis https://github.com/axic/pm-contracts.git solidity-050
|
|
||||||
|
@ -24,8 +24,9 @@ set -e
|
|||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
verify_input "$1"
|
verify_input "$@"
|
||||||
SOLJSON="$1"
|
BINARY_TYPE="$1"
|
||||||
|
BINARY_PATH="$2"
|
||||||
|
|
||||||
function compile_fn { yarn run provision:token:contracts; }
|
function compile_fn { yarn run provision:token:contracts; }
|
||||||
function test_fn { yarn run test:contracts; }
|
function test_fn { yarn run test:contracts; }
|
||||||
@ -38,11 +39,16 @@ function colony_test
|
|||||||
local min_optimizer_level=3
|
local min_optimizer_level=3
|
||||||
local max_optimizer_level=3
|
local max_optimizer_level=3
|
||||||
|
|
||||||
setup_solcjs "$DIR" "$SOLJSON"
|
local selected_optimizer_levels
|
||||||
|
selected_optimizer_levels=$(circleci_select_steps "$(seq "$min_optimizer_level" "$max_optimizer_level")")
|
||||||
|
print_optimizer_levels_or_exit "$selected_optimizer_levels"
|
||||||
|
|
||||||
|
setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH"
|
||||||
download_project "$repo" "$branch" "$DIR"
|
download_project "$repo" "$branch" "$DIR"
|
||||||
|
[[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH"
|
||||||
|
|
||||||
neutralize_package_json_hooks
|
neutralize_package_json_hooks
|
||||||
force_truffle_compiler_settings "$config_file" "${DIR}/solc" "$min_optimizer_level"
|
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$min_optimizer_level"
|
||||||
yarn
|
yarn
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
||||||
@ -52,10 +58,10 @@ function colony_test
|
|||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
force_solc_modules "${DIR}/solc"
|
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc"
|
||||||
|
|
||||||
for level in $(seq "$min_optimizer_level" "$max_optimizer_level"); do
|
for level in $selected_optimizer_levels; do
|
||||||
truffle_run_test "$config_file" "${DIR}/solc" "$level" compile_fn test_fn
|
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$level" compile_fn test_fn
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,59 +24,64 @@ set -e
|
|||||||
|
|
||||||
CURRENT_EVM_VERSION=london
|
CURRENT_EVM_VERSION=london
|
||||||
|
|
||||||
|
function print_optimizer_levels_or_exit
|
||||||
|
{
|
||||||
|
local selected_levels="$1"
|
||||||
|
|
||||||
|
[[ $selected_levels != "" ]] || { printWarning "No steps to run. Exiting."; exit 0; }
|
||||||
|
|
||||||
|
printLog "Selected optimizer levels: ${selected_levels}"
|
||||||
|
}
|
||||||
|
|
||||||
function verify_input
|
function verify_input
|
||||||
{
|
{
|
||||||
if [ ! -f "$1" ]; then
|
local binary_type="$1"
|
||||||
printError "Usage: $0 <path to soljson.js>"
|
local binary_path="$2"
|
||||||
exit 1
|
|
||||||
fi
|
(( $# == 2 )) || fail "Usage: $0 native|solcjs <path to solc or soljson.js>"
|
||||||
|
[[ $binary_type == native || $binary_type == solcjs ]] || fail "Invalid binary type: '${binary_type}'. Must be either 'native' or 'solcjs'."
|
||||||
|
[[ -f "$binary_path" ]] || fail "The compiler binary does not exist at '${binary_path}'"
|
||||||
}
|
}
|
||||||
|
|
||||||
function verify_version_input
|
function setup_solc
|
||||||
{
|
{
|
||||||
if [ -z "$1" ] || [ ! -f "$1" ] || [ -z "$2" ]; then
|
local test_dir="$1"
|
||||||
printError "Usage: $0 <path to soljson.js> <version>"
|
local binary_type="$2"
|
||||||
exit 1
|
local binary_path="$3"
|
||||||
fi
|
local solcjs_branch="${4:-master}"
|
||||||
}
|
local install_dir="${5:-solc/}"
|
||||||
|
|
||||||
function setup
|
[[ $binary_type == native || $binary_type == solcjs ]] || assertFail
|
||||||
{
|
|
||||||
local soljson="$1"
|
|
||||||
local branch="$2"
|
|
||||||
|
|
||||||
setup_solcjs "$DIR" "$soljson" "$branch" "solc"
|
cd "$test_dir"
|
||||||
cd solc
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup_solcjs
|
if [[ $binary_type == solcjs ]]
|
||||||
{
|
then
|
||||||
local dir="$1"
|
|
||||||
local soljson="$2"
|
|
||||||
local branch="${3:-master}"
|
|
||||||
local path="${4:-solc/}"
|
|
||||||
|
|
||||||
cd "$dir"
|
|
||||||
printLog "Setting up solc-js..."
|
printLog "Setting up solc-js..."
|
||||||
git clone --depth 1 -b "$branch" https://github.com/ethereum/solc-js.git "$path"
|
git clone --depth 1 -b "$solcjs_branch" https://github.com/ethereum/solc-js.git "$install_dir"
|
||||||
|
|
||||||
cd "$path"
|
|
||||||
|
|
||||||
|
pushd "$install_dir"
|
||||||
npm install
|
npm install
|
||||||
cp "$soljson" soljson.js
|
cp "$binary_path" soljson.js
|
||||||
SOLCVERSION=$(./solcjs --version)
|
SOLCVERSION=$(./solcjs --version)
|
||||||
printLog "Using solcjs version $SOLCVERSION"
|
popd
|
||||||
cd ..
|
else
|
||||||
|
printLog "Setting up solc..."
|
||||||
|
SOLCVERSION=$("$binary_path" --version | tail -n 1 | sed -n -E 's/^Version: (.*)$/\1/p')
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOLCVERSION_SHORT=$(echo "$SOLCVERSION" | sed -En 's/^([0-9.]+).*\+commit\.[0-9a-f]+.*$/\1/p')
|
||||||
|
printLog "Using compiler version $SOLCVERSION"
|
||||||
}
|
}
|
||||||
|
|
||||||
function download_project
|
function download_project
|
||||||
{
|
{
|
||||||
local repo="$1"
|
local repo="$1"
|
||||||
local branch="$2"
|
local solcjs_branch="$2"
|
||||||
local dir="$3"
|
local test_dir="$3"
|
||||||
|
|
||||||
printLog "Cloning $branch of $repo..."
|
printLog "Cloning $solcjs_branch of $repo..."
|
||||||
git clone --depth 1 "$repo" -b "$branch" "$dir/ext"
|
git clone --depth 1 "$repo" -b "$solcjs_branch" "$test_dir/ext"
|
||||||
cd ext
|
cd ext
|
||||||
echo "Current commit hash: $(git rev-parse HEAD)"
|
echo "Current commit hash: $(git rev-parse HEAD)"
|
||||||
}
|
}
|
||||||
@ -134,13 +139,19 @@ function force_solc_modules
|
|||||||
function force_truffle_compiler_settings
|
function force_truffle_compiler_settings
|
||||||
{
|
{
|
||||||
local config_file="$1"
|
local config_file="$1"
|
||||||
local solc_path="$2"
|
local binary_type="$2"
|
||||||
local level="$3"
|
local solc_path="$3"
|
||||||
local evm_version="${4:-"$CURRENT_EVM_VERSION"}"
|
local level="$4"
|
||||||
|
local evm_version="${5:-"$CURRENT_EVM_VERSION"}"
|
||||||
|
|
||||||
|
[[ $binary_type == native || $binary_type == solcjs ]] || assertFail
|
||||||
|
|
||||||
|
[[ $binary_type == native ]] && local solc_path="native"
|
||||||
|
|
||||||
printLog "Forcing Truffle compiler settings..."
|
printLog "Forcing Truffle compiler settings..."
|
||||||
echo "-------------------------------------"
|
echo "-------------------------------------"
|
||||||
echo "Config file: $config_file"
|
echo "Config file: $config_file"
|
||||||
|
echo "Binary type: $binary_type"
|
||||||
echo "Compiler path: $solc_path"
|
echo "Compiler path: $solc_path"
|
||||||
echo "Optimization level: $level"
|
echo "Optimization level: $level"
|
||||||
echo "Optimizer settings: $(optimizer_settings_for_level "$level")"
|
echo "Optimizer settings: $(optimizer_settings_for_level "$level")"
|
||||||
@ -152,6 +163,42 @@ function force_truffle_compiler_settings
|
|||||||
echo "module.exports['compilers'] = $(truffle_compiler_settings "$solc_path" "$level" "$evm_version");" >> "$config_file"
|
echo "module.exports['compilers'] = $(truffle_compiler_settings "$solc_path" "$level" "$evm_version");" >> "$config_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function force_hardhat_compiler_binary
|
||||||
|
{
|
||||||
|
local config_file="$1"
|
||||||
|
local binary_type="$2"
|
||||||
|
local solc_path="$3"
|
||||||
|
|
||||||
|
printLog "Configuring Hardhat..."
|
||||||
|
echo "-------------------------------------"
|
||||||
|
echo "Config file: ${config_file}"
|
||||||
|
echo "Binary type: ${binary_type}"
|
||||||
|
echo "Compiler path: ${solc_path}"
|
||||||
|
hardhat_solc_build_subtask "$SOLCVERSION_SHORT" "$SOLCVERSION" "$binary_type" "$solc_path" >> "$config_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
function force_hardhat_compiler_settings
|
||||||
|
{
|
||||||
|
local config_file="$1"
|
||||||
|
local level="$2"
|
||||||
|
local evm_version="${3:-"$CURRENT_EVM_VERSION"}"
|
||||||
|
|
||||||
|
printLog "Configuring Hardhat..."
|
||||||
|
echo "-------------------------------------"
|
||||||
|
echo "Config file: ${config_file}"
|
||||||
|
echo "Optimization level: ${level}"
|
||||||
|
echo "Optimizer settings: $(optimizer_settings_for_level "$level")"
|
||||||
|
echo "EVM version: ${evm_version}"
|
||||||
|
echo "Compiler version: ${SOLCVERSION_SHORT}"
|
||||||
|
echo "Compiler version (full): ${SOLCVERSION}"
|
||||||
|
echo "-------------------------------------"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo -n 'module.exports["solidity"] = '
|
||||||
|
hardhat_compiler_settings "$SOLCVERSION_SHORT" "$level" "$evm_version"
|
||||||
|
} >> "$config_file"
|
||||||
|
}
|
||||||
|
|
||||||
function truffle_verify_compiler_version
|
function truffle_verify_compiler_version
|
||||||
{
|
{
|
||||||
local solc_version="$1"
|
local solc_version="$1"
|
||||||
@ -161,11 +208,26 @@ function truffle_verify_compiler_version
|
|||||||
grep "$full_solc_version" --with-filename --recursive build/contracts || fail "Wrong compiler version detected."
|
grep "$full_solc_version" --with-filename --recursive build/contracts || fail "Wrong compiler version detected."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hardhat_verify_compiler_version
|
||||||
|
{
|
||||||
|
local solc_version="$1"
|
||||||
|
local full_solc_version="$2"
|
||||||
|
|
||||||
|
printLog "Verify that the correct version (${solc_version}/${full_solc_version}) of the compiler was used to compile the contracts..."
|
||||||
|
grep '"solcVersion": "'"${solc_version}"'"' --with-filename artifacts/build-info/*.json || fail "Wrong compiler version detected."
|
||||||
|
grep '"solcLongVersion": "'"${full_solc_version}"'"' --with-filename artifacts/build-info/*.json || fail "Wrong compiler version detected."
|
||||||
|
}
|
||||||
|
|
||||||
function truffle_clean
|
function truffle_clean
|
||||||
{
|
{
|
||||||
rm -rf build/
|
rm -rf build/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hardhat_clean
|
||||||
|
{
|
||||||
|
rm -rf artifacts/ cache/
|
||||||
|
}
|
||||||
|
|
||||||
function run_test
|
function run_test
|
||||||
{
|
{
|
||||||
local compile_fn="$1"
|
local compile_fn="$1"
|
||||||
@ -189,12 +251,21 @@ function optimizer_settings_for_level
|
|||||||
2) echo "{enabled: true}" ;;
|
2) echo "{enabled: true}" ;;
|
||||||
3) echo "{enabled: true, details: {yul: true}}" ;;
|
3) echo "{enabled: true, details: {yul: true}}" ;;
|
||||||
*)
|
*)
|
||||||
printError "Optimizer level not found. Please define OPTIMIZER_LEVEL=[1, 2, 3]"
|
fail "Optimizer level not found. Please define OPTIMIZER_LEVEL=[1, 2, 3]"
|
||||||
exit 1
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function replace_global_solc
|
||||||
|
{
|
||||||
|
local solc_path="$1"
|
||||||
|
|
||||||
|
[[ ! -e solc ]] || fail "A file named 'solc' already exists in '${PWD}'."
|
||||||
|
|
||||||
|
ln -s "$solc_path" solc
|
||||||
|
export PATH="$PWD:$PATH"
|
||||||
|
}
|
||||||
|
|
||||||
function truffle_compiler_settings
|
function truffle_compiler_settings
|
||||||
{
|
{
|
||||||
local solc_path="$1"
|
local solc_path="$1"
|
||||||
@ -212,6 +283,45 @@ function truffle_compiler_settings
|
|||||||
echo "}"
|
echo "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hardhat_solc_build_subtask {
|
||||||
|
local solc_version="$1"
|
||||||
|
local full_solc_version="$2"
|
||||||
|
local binary_type="$3"
|
||||||
|
local solc_path="$4"
|
||||||
|
|
||||||
|
[[ $binary_type == native || $binary_type == solcjs ]] || assertFail
|
||||||
|
|
||||||
|
[[ $binary_type == native ]] && local is_solcjs=false
|
||||||
|
[[ $binary_type == solcjs ]] && local is_solcjs=true
|
||||||
|
|
||||||
|
echo "const {TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD} = require('hardhat/builtin-tasks/task-names');"
|
||||||
|
echo "const assert = require('assert');"
|
||||||
|
echo
|
||||||
|
echo "subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async (args, hre, runSuper) => {"
|
||||||
|
echo " assert(args.solcVersion == '${solc_version}', 'Unexpected solc version: ' + args.solcVersion)"
|
||||||
|
echo " return {"
|
||||||
|
echo " compilerPath: '$(realpath "$solc_path")',"
|
||||||
|
echo " isSolcJs: ${is_solcjs},"
|
||||||
|
echo " version: args.solcVersion,"
|
||||||
|
echo " longVersion: '${full_solc_version}'"
|
||||||
|
echo " }"
|
||||||
|
echo "})"
|
||||||
|
}
|
||||||
|
|
||||||
|
function hardhat_compiler_settings {
|
||||||
|
local solc_version="$1"
|
||||||
|
local level="$2"
|
||||||
|
local evm_version="$3"
|
||||||
|
|
||||||
|
echo "{"
|
||||||
|
echo " version: '${solc_version}',"
|
||||||
|
echo " settings: {"
|
||||||
|
echo " optimizer: $(optimizer_settings_for_level "$level"),"
|
||||||
|
echo " evmVersion: '${evm_version}'"
|
||||||
|
echo " }"
|
||||||
|
echo "}"
|
||||||
|
}
|
||||||
|
|
||||||
function compile_and_run_test
|
function compile_and_run_test
|
||||||
{
|
{
|
||||||
local compile_fn="$1"
|
local compile_fn="$1"
|
||||||
@ -233,16 +343,29 @@ function compile_and_run_test
|
|||||||
function truffle_run_test
|
function truffle_run_test
|
||||||
{
|
{
|
||||||
local config_file="$1"
|
local config_file="$1"
|
||||||
local solc_path="$2"
|
local binary_type="$2"
|
||||||
local optimizer_level="$3"
|
local solc_path="$3"
|
||||||
local compile_fn="$4"
|
local optimizer_level="$4"
|
||||||
local test_fn="$5"
|
local compile_fn="$5"
|
||||||
|
local test_fn="$6"
|
||||||
|
|
||||||
truffle_clean
|
truffle_clean
|
||||||
force_truffle_compiler_settings "$config_file" "$solc_path" "$optimizer_level"
|
force_truffle_compiler_settings "$config_file" "$binary_type" "$solc_path" "$optimizer_level"
|
||||||
compile_and_run_test compile_fn test_fn truffle_verify_compiler_version
|
compile_and_run_test compile_fn test_fn truffle_verify_compiler_version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hardhat_run_test
|
||||||
|
{
|
||||||
|
local config_file="$1"
|
||||||
|
local optimizer_level="$2"
|
||||||
|
local compile_fn="$3"
|
||||||
|
local test_fn="$4"
|
||||||
|
|
||||||
|
hardhat_clean
|
||||||
|
force_hardhat_compiler_settings "$config_file" "$optimizer_level"
|
||||||
|
compile_and_run_test compile_fn test_fn hardhat_verify_compiler_version
|
||||||
|
}
|
||||||
|
|
||||||
function external_test
|
function external_test
|
||||||
{
|
{
|
||||||
local name="$1"
|
local name="$1"
|
||||||
@ -252,10 +375,7 @@ function external_test
|
|||||||
echo "==========================="
|
echo "==========================="
|
||||||
DIR=$(mktemp -d -t "ext-test-${name}-XXXXXX")
|
DIR=$(mktemp -d -t "ext-test-${name}-XXXXXX")
|
||||||
(
|
(
|
||||||
if [ -z "$main_fn" ]; then
|
[[ "$main_fn" != "" ]] || fail "Test main function not defined."
|
||||||
printError "Test main function not defined."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
$main_fn
|
$main_fn
|
||||||
)
|
)
|
||||||
rm -rf "$DIR"
|
rm -rf "$DIR"
|
||||||
|
@ -24,8 +24,9 @@ set -e
|
|||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
verify_input "$1"
|
verify_input "$@"
|
||||||
export SOLJSON="$1"
|
BINARY_TYPE="$1"
|
||||||
|
BINARY_PATH="$2"
|
||||||
|
|
||||||
function compile_fn { npx truffle compile; }
|
function compile_fn { npx truffle compile; }
|
||||||
function test_fn { npm run test; }
|
function test_fn { npm run test; }
|
||||||
@ -38,22 +39,27 @@ function ens_test
|
|||||||
local min_optimizer_level=1
|
local min_optimizer_level=1
|
||||||
local max_optimizer_level=3
|
local max_optimizer_level=3
|
||||||
|
|
||||||
setup_solcjs "$DIR" "$SOLJSON"
|
local selected_optimizer_levels
|
||||||
|
selected_optimizer_levels=$(circleci_select_steps "$(seq "$min_optimizer_level" "$max_optimizer_level")")
|
||||||
|
print_optimizer_levels_or_exit "$selected_optimizer_levels"
|
||||||
|
|
||||||
|
setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH"
|
||||||
download_project "$repo" "$branch" "$DIR"
|
download_project "$repo" "$branch" "$DIR"
|
||||||
|
[[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH"
|
||||||
|
|
||||||
# Use latest Truffle. Older versions crash on the output from 0.8.0.
|
# Use latest Truffle. Older versions crash on the output from 0.8.0.
|
||||||
force_truffle_version ^5.1.55
|
force_truffle_version ^5.1.55
|
||||||
|
|
||||||
neutralize_package_lock
|
neutralize_package_lock
|
||||||
neutralize_package_json_hooks
|
neutralize_package_json_hooks
|
||||||
force_truffle_compiler_settings "$config_file" "${DIR}/solc" "$min_optimizer_level"
|
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$min_optimizer_level"
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
force_solc_modules "${DIR}/solc"
|
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc"
|
||||||
|
|
||||||
for level in $(seq "$min_optimizer_level" "$max_optimizer_level"); do
|
for level in $selected_optimizer_levels; do
|
||||||
truffle_run_test "$config_file" "${DIR}/solc" "$level" compile_fn test_fn
|
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$level" compile_fn test_fn
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,10 @@ set -e
|
|||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
verify_input "$1"
|
verify_input "$@"
|
||||||
SOLJSON="$1"
|
BINARY_TYPE="$1"
|
||||||
|
BINARY_PATH="$2"
|
||||||
|
|
||||||
function install_fn { npm install --package-lock; }
|
|
||||||
function compile_fn { npx truffle compile; }
|
function compile_fn { npx truffle compile; }
|
||||||
function test_fn { npm test; }
|
function test_fn { npm test; }
|
||||||
|
|
||||||
@ -39,22 +39,27 @@ function gnosis_safe_test
|
|||||||
local min_optimizer_level=2
|
local min_optimizer_level=2
|
||||||
local max_optimizer_level=3
|
local max_optimizer_level=3
|
||||||
|
|
||||||
setup_solcjs "$DIR" "$SOLJSON"
|
local selected_optimizer_levels
|
||||||
|
selected_optimizer_levels=$(circleci_select_steps "$(seq "$min_optimizer_level" "$max_optimizer_level")")
|
||||||
|
print_optimizer_levels_or_exit "$selected_optimizer_levels"
|
||||||
|
|
||||||
|
setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH"
|
||||||
download_project "$repo" "$branch" "$DIR"
|
download_project "$repo" "$branch" "$DIR"
|
||||||
|
[[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH"
|
||||||
|
|
||||||
sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json
|
sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json
|
||||||
sed -i -E 's|"@gnosis.pm/util-contracts": "[^"]+"|"@gnosis.pm/util-contracts": "github:solidity-external-tests/util-contracts#solc-7_080"|g' package.json
|
sed -i -E 's|"@gnosis.pm/util-contracts": "[^"]+"|"@gnosis.pm/util-contracts": "github:solidity-external-tests/util-contracts#solc-7_080"|g' package.json
|
||||||
|
|
||||||
neutralize_package_lock
|
neutralize_package_lock
|
||||||
neutralize_package_json_hooks
|
neutralize_package_json_hooks
|
||||||
force_truffle_compiler_settings "$config_file" "${DIR}/solc" "$min_optimizer_level"
|
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$min_optimizer_level"
|
||||||
npm install --package-lock
|
npm install --package-lock
|
||||||
|
|
||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
force_solc_modules "${DIR}/solc"
|
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc"
|
||||||
|
|
||||||
for level in $(seq "$min_optimizer_level" "$max_optimizer_level"); do
|
for level in $selected_optimizer_levels; do
|
||||||
truffle_run_test "$config_file" "${DIR}/solc" "$level" compile_fn test_fn
|
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$level" compile_fn test_fn
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,9 @@ set -e
|
|||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
verify_input "$1"
|
verify_input "$@"
|
||||||
SOLJSON="$1"
|
BINARY_TYPE="$1"
|
||||||
|
BINARY_PATH="$2"
|
||||||
|
|
||||||
function compile_fn { npx truffle compile; }
|
function compile_fn { npx truffle compile; }
|
||||||
function test_fn { npm test; }
|
function test_fn { npm test; }
|
||||||
@ -38,21 +39,26 @@ function gnosis_safe_test
|
|||||||
local min_optimizer_level=2
|
local min_optimizer_level=2
|
||||||
local max_optimizer_level=3
|
local max_optimizer_level=3
|
||||||
|
|
||||||
setup_solcjs "$DIR" "$SOLJSON"
|
local selected_optimizer_levels
|
||||||
|
selected_optimizer_levels=$(circleci_select_steps "$(seq "$min_optimizer_level" "$max_optimizer_level")")
|
||||||
|
print_optimizer_levels_or_exit "$selected_optimizer_levels"
|
||||||
|
|
||||||
|
setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH"
|
||||||
download_project "$repo" "$branch" "$DIR"
|
download_project "$repo" "$branch" "$DIR"
|
||||||
|
[[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH"
|
||||||
|
|
||||||
sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json
|
sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json
|
||||||
|
|
||||||
neutralize_package_lock
|
neutralize_package_lock
|
||||||
neutralize_package_json_hooks
|
neutralize_package_json_hooks
|
||||||
force_truffle_compiler_settings "$config_file" "${DIR}/solc" "$min_optimizer_level"
|
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$min_optimizer_level"
|
||||||
npm install --package-lock
|
npm install --package-lock
|
||||||
|
|
||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
force_solc_modules "${DIR}/solc"
|
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc"
|
||||||
|
|
||||||
for level in $(seq "$min_optimizer_level" "$max_optimizer_level"); do
|
for level in $selected_optimizer_levels; do
|
||||||
truffle_run_test "$config_file" "${DIR}/solc" "$level" compile_fn test_fn
|
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$level" compile_fn test_fn
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,11 @@ set -e
|
|||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
verify_version_input "$1" "$2"
|
|
||||||
SOLJSON="$1"
|
SOLJSON="$1"
|
||||||
VERSION="$2"
|
VERSION="$2"
|
||||||
|
|
||||||
|
[[ $SOLJSON != "" && -f "$SOLJSON" && $VERSION != "" ]] || fail "Usage: $0 <path to soljson.js> <version>"
|
||||||
|
|
||||||
function compile_fn { echo "Nothing to compile."; }
|
function compile_fn { echo "Nothing to compile."; }
|
||||||
function test_fn { npm test; }
|
function test_fn { npm test; }
|
||||||
|
|
||||||
@ -37,7 +38,8 @@ function solcjs_test
|
|||||||
SOLCJS_INPUT_DIR="$TEST_DIR"/test/externalTests/solc-js
|
SOLCJS_INPUT_DIR="$TEST_DIR"/test/externalTests/solc-js
|
||||||
|
|
||||||
# set up solc-js on the branch specified
|
# set up solc-js on the branch specified
|
||||||
setup "$SOLJSON" master
|
setup_solc "$DIR" solcjs "$SOLJSON" master solc/
|
||||||
|
cd solc/
|
||||||
|
|
||||||
printLog "Updating index.js file..."
|
printLog "Updating index.js file..."
|
||||||
echo "require('./determinism.js');" >> test/index.js
|
echo "require('./determinism.js');" >> test/index.js
|
||||||
|
@ -24,32 +24,37 @@ set -e
|
|||||||
source scripts/common.sh
|
source scripts/common.sh
|
||||||
source test/externalTests/common.sh
|
source test/externalTests/common.sh
|
||||||
|
|
||||||
verify_input "$1"
|
verify_input "$@"
|
||||||
SOLJSON="$1"
|
BINARY_TYPE="$1"
|
||||||
|
BINARY_PATH="$2"
|
||||||
|
|
||||||
function compile_fn { npx truffle compile; }
|
function compile_fn { npm run compile; }
|
||||||
function test_fn { npm run test; }
|
function test_fn { npm test; }
|
||||||
|
|
||||||
function zeppelin_test
|
function zeppelin_test
|
||||||
{
|
{
|
||||||
local repo="https://github.com/OpenZeppelin/openzeppelin-contracts.git"
|
local repo="https://github.com/OpenZeppelin/openzeppelin-contracts.git"
|
||||||
local branch=master
|
local branch=master
|
||||||
local config_file="truffle-config.js"
|
local config_file="hardhat.config.js"
|
||||||
local min_optimizer_level=1
|
local min_optimizer_level=1
|
||||||
local max_optimizer_level=3
|
local max_optimizer_level=3
|
||||||
|
|
||||||
setup_solcjs "$DIR" "$SOLJSON"
|
local selected_optimizer_levels
|
||||||
|
selected_optimizer_levels=$(circleci_select_steps "$(seq "$min_optimizer_level" "$max_optimizer_level")")
|
||||||
|
print_optimizer_levels_or_exit "$selected_optimizer_levels"
|
||||||
|
|
||||||
|
setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH"
|
||||||
download_project "$repo" "$branch" "$DIR"
|
download_project "$repo" "$branch" "$DIR"
|
||||||
|
|
||||||
neutralize_package_json_hooks
|
neutralize_package_json_hooks
|
||||||
force_truffle_compiler_settings "$config_file" "${DIR}/solc" "$min_optimizer_level"
|
force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH"
|
||||||
|
force_hardhat_compiler_settings "$config_file" "$min_optimizer_level"
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
replace_version_pragmas
|
replace_version_pragmas
|
||||||
force_solc_modules "${DIR}/solc"
|
|
||||||
|
|
||||||
for level in $(seq "$min_optimizer_level" "$max_optimizer_level"); do
|
for level in $selected_optimizer_levels; do
|
||||||
truffle_run_test "$config_file" "${DIR}/solc" "$level" compile_fn test_fn
|
hardhat_run_test "$config_file" "$level" compile_fn test_fn
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,33 @@
|
|||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::test;
|
||||||
|
|
||||||
|
namespace boost::test_tools::tt_detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct print_log_value<std::optional<int>>
|
||||||
|
{
|
||||||
|
void operator()(std::ostream& _out, std::optional<int> const& _value) const
|
||||||
|
{
|
||||||
|
_out << (_value ? to_string(*_value) : "[nullopt]");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct print_log_value<nullopt_t>
|
||||||
|
{
|
||||||
|
void operator()(std::ostream& _out, nullopt_t const&) const
|
||||||
|
{
|
||||||
|
_out << "[nullopt]";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace boost::test_tools::tt_detail
|
||||||
|
|
||||||
|
|
||||||
namespace solidity::langutil::test
|
namespace solidity::langutil::test
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -48,6 +75,62 @@ BOOST_AUTO_TEST_CASE(test_fail)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::optional<int> toPosition(int _line, int _column, string const& _text)
|
||||||
|
{
|
||||||
|
return CharStream{_text, "source"}.translateLineColumnToPosition(
|
||||||
|
LineColumn{_line, _column}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(translateLineColumnToPosition)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(-1, 0, "ABC"), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, -1, "ABC"), nullopt);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 0, ""), 0);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 0, ""), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 1, ""), nullopt);
|
||||||
|
|
||||||
|
// With last line containing no LF
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 0, "ABC"), 0);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 1, "ABC"), 1);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 2, "ABC"), 2);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 3, "ABC"), 3);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 4, "ABC"), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 0, "ABC"), nullopt);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 3, "ABC\nDEF"), 3);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 4, "ABC\nDEF"), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 0, "ABC\nDEF"), 4);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 1, "ABC\nDEF"), 5);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 2, "ABC\nDEF"), 6);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 3, "ABC\nDEF"), 7);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 4, "ABC\nDEF"), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 0, "ABC\nDEF"), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 1, "ABC\nDEF"), nullopt);
|
||||||
|
|
||||||
|
// With last line containing LF
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 0, "ABC\nDEF\n"), 0);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 1, "ABC\nDEF\n"), 1);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(0, 2, "ABC\nDEF\n"), 2);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 0, "ABC\nDEF\n"), 4);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 1, "ABC\nDEF\n"), 5);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 2, "ABC\nDEF\n"), 6);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 3, "ABC\nDEF\n"), 7);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(1, 4, "ABC\nDEF\n"), nullopt);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 0, "ABC\nDEF\n"), 8);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 1, "ABC\nDEF\n"), nullopt);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 0, "ABC\nDEF\nGHI\n"), 8);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 1, "ABC\nDEF\nGHI\n"), 9);
|
||||||
|
BOOST_CHECK_EQUAL(toPosition(2, 2, "ABC\nDEF\nGHI\n"), 10);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
} // end namespaces
|
}
|
||||||
|
@ -16,17 +16,20 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
|
||||||
#include <test/libsolidity/ASTJSONTest.h>
|
|
||||||
#include <test/Common.h>
|
|
||||||
#include <libsolutil/AnsiColorized.h>
|
|
||||||
#include <liblangutil/SourceReferenceFormatter.h>
|
#include <liblangutil/SourceReferenceFormatter.h>
|
||||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||||
#include <libsolidity/interface/CompilerStack.h>
|
#include <libsolutil/AnsiColorized.h>
|
||||||
|
#include <libsolutil/CommonIO.h>
|
||||||
|
|
||||||
|
#include <test/Common.h>
|
||||||
|
#include <test/libsolidity/ASTJSONTest.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/throw_exception.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/throw_exception.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -72,8 +75,13 @@ ASTJSONTest::ASTJSONTest(string const& _filename)
|
|||||||
if (!boost::algorithm::ends_with(_filename, ".sol"))
|
if (!boost::algorithm::ends_with(_filename, ".sol"))
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid test contract file name: \"" + _filename + "\"."));
|
BOOST_THROW_EXCEPTION(runtime_error("Invalid test contract file name: \"" + _filename + "\"."));
|
||||||
|
|
||||||
m_astFilename = _filename.substr(0, _filename.size() - 4) + ".json";
|
string_view baseName = _filename;
|
||||||
m_astParseOnlyFilename = _filename.substr(0, _filename.size() - 4) + "_parseOnly.json";
|
baseName.remove_suffix(4);
|
||||||
|
|
||||||
|
m_variants = {
|
||||||
|
TestVariant(baseName, CompilerStack::State::Parsed),
|
||||||
|
TestVariant(baseName, CompilerStack::State::AnalysisPerformed),
|
||||||
|
};
|
||||||
|
|
||||||
ifstream file(_filename);
|
ifstream file(_filename);
|
||||||
if (!file)
|
if (!file)
|
||||||
@ -102,26 +110,13 @@ ASTJSONTest::ASTJSONTest(string const& _filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_sources.emplace_back(sourceName.empty() ? "a" : sourceName, source);
|
m_sources.emplace_back(sourceName.empty() ? "a" : sourceName, source);
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
file.open(m_astFilename);
|
|
||||||
if (file)
|
for (TestVariant& variant: m_variants)
|
||||||
{
|
{
|
||||||
string line;
|
variant.expectation = readFileAsString(variant.astFilename());
|
||||||
while (getline(file, line))
|
boost::replace_all(variant.expectation, "\r\n", "\n");
|
||||||
m_expectation += line + "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
|
||||||
file.open(m_astParseOnlyFilename);
|
|
||||||
if (file)
|
|
||||||
{
|
|
||||||
string line;
|
|
||||||
while (getline(file, line))
|
|
||||||
m_expectationParseOnly += line + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||||
@ -135,97 +130,76 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi
|
|||||||
sources[m_sources[i].first] = m_sources[i].second;
|
sources[m_sources[i].first] = m_sources[i].second;
|
||||||
sourceIndices[m_sources[i].first] = static_cast<unsigned>(i + 1);
|
sourceIndices[m_sources[i].first] = static_cast<unsigned>(i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool resultsMatch = true;
|
||||||
|
|
||||||
|
for (TestVariant& variant: m_variants)
|
||||||
|
{
|
||||||
|
c.reset();
|
||||||
c.setSources(sources);
|
c.setSources(sources);
|
||||||
c.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
c.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
||||||
|
|
||||||
|
if (!c.parseAndAnalyze(variant.stopAfter))
|
||||||
if (!c.compile(CompilerStack::State::Parsed))
|
|
||||||
{
|
{
|
||||||
|
// Ignore non-fatal analysis errors, we only want to export.
|
||||||
|
if (c.state() > CompilerStack::State::Parsed)
|
||||||
|
continue;
|
||||||
|
|
||||||
SourceReferenceFormatter formatter(_stream, c, _formatted, false);
|
SourceReferenceFormatter formatter(_stream, c, _formatted, false);
|
||||||
formatter.printErrorInformation(c.errors());
|
formatter.printErrorInformation(c.errors());
|
||||||
return TestResult::FatalError;
|
return TestResult::FatalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool resultsMatch = runTest(
|
resultsMatch = resultsMatch && runTest(
|
||||||
m_expectationParseOnly,
|
variant,
|
||||||
m_resultParseOnly,
|
|
||||||
sourceIndices,
|
sourceIndices,
|
||||||
c,
|
c,
|
||||||
"parseOnly",
|
|
||||||
_stream,
|
_stream,
|
||||||
_linePrefix,
|
_linePrefix,
|
||||||
_formatted
|
_formatted
|
||||||
);
|
);
|
||||||
|
|
||||||
c.reset();
|
|
||||||
c.setSources(sources);
|
|
||||||
c.setEVMVersion(solidity::test::CommonOptions::get().evmVersion());
|
|
||||||
if (!c.parse())
|
|
||||||
{
|
|
||||||
// Empty Expectations means we expect failure
|
|
||||||
if (m_expectation.empty())
|
|
||||||
return resultsMatch ? TestResult::Success : TestResult::Failure;
|
|
||||||
|
|
||||||
SourceReferenceFormatter{_stream, c, _formatted, false}
|
|
||||||
.printErrorInformation(c.errors());
|
|
||||||
return TestResult::FatalError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.analyze();
|
|
||||||
|
|
||||||
resultsMatch = runTest(
|
|
||||||
m_expectation,
|
|
||||||
m_result,
|
|
||||||
sourceIndices,
|
|
||||||
c,
|
|
||||||
"",
|
|
||||||
_stream,
|
|
||||||
_linePrefix,
|
|
||||||
_formatted
|
|
||||||
) && resultsMatch;
|
|
||||||
|
|
||||||
return resultsMatch ? TestResult::Success : TestResult::Failure;
|
return resultsMatch ? TestResult::Success : TestResult::Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJSONTest::runTest(
|
bool ASTJSONTest::runTest(
|
||||||
string& _expectation,
|
TestVariant& _variant,
|
||||||
string& _result,
|
|
||||||
map<string, unsigned> const& _sourceIndices,
|
map<string, unsigned> const& _sourceIndices,
|
||||||
CompilerStack& _compiler,
|
CompilerStack& _compiler,
|
||||||
string const& _variation,
|
|
||||||
ostream& _stream,
|
ostream& _stream,
|
||||||
string const& _linePrefix,
|
string const& _linePrefix,
|
||||||
bool const _formatted
|
bool const _formatted
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (m_sources.size() > 1)
|
if (m_sources.size() > 1)
|
||||||
_result += "[\n";
|
_variant.result += "[\n";
|
||||||
|
|
||||||
for (size_t i = 0; i < m_sources.size(); i++)
|
for (size_t i = 0; i < m_sources.size(); i++)
|
||||||
{
|
{
|
||||||
ostringstream result;
|
ostringstream result;
|
||||||
ASTJsonConverter(_compiler.state(), _sourceIndices).print(result, _compiler.ast(m_sources[i].first));
|
ASTJsonConverter(_compiler.state(), _sourceIndices).print(result, _compiler.ast(m_sources[i].first));
|
||||||
_result += result.str();
|
_variant.result += result.str();
|
||||||
if (i != m_sources.size() - 1)
|
if (i != m_sources.size() - 1)
|
||||||
_result += ",";
|
_variant.result += ",";
|
||||||
_result += "\n";
|
_variant.result += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_sources.size() > 1)
|
if (m_sources.size() > 1)
|
||||||
_result += "]\n";
|
_variant.result += "]\n";
|
||||||
|
|
||||||
replaceTagWithVersion(_expectation);
|
replaceTagWithVersion(_variant.expectation);
|
||||||
|
|
||||||
if (_expectation != _result)
|
if (_variant.expectation != _variant.result)
|
||||||
{
|
{
|
||||||
string nextIndentLevel = _linePrefix + " ";
|
string nextIndentLevel = _linePrefix + " ";
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) <<
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) <<
|
||||||
_linePrefix <<
|
_linePrefix <<
|
||||||
"Expected result" <<
|
"Expected result" <<
|
||||||
(!_variation.empty() ? " (" + _variation + "):" : ":") <<
|
(!_variant.name().empty() ? " (" + _variant.name() + "):" : ":") <<
|
||||||
endl;
|
endl;
|
||||||
{
|
{
|
||||||
istringstream stream(_expectation);
|
istringstream stream(_variant.expectation);
|
||||||
string line;
|
string line;
|
||||||
while (getline(stream, line))
|
while (getline(stream, line))
|
||||||
_stream << nextIndentLevel << line << endl;
|
_stream << nextIndentLevel << line << endl;
|
||||||
@ -235,10 +209,10 @@ bool ASTJSONTest::runTest(
|
|||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) <<
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) <<
|
||||||
_linePrefix <<
|
_linePrefix <<
|
||||||
"Obtained result" <<
|
"Obtained result" <<
|
||||||
(!_variation.empty() ? " (" + _variation + "):" : ":") <<
|
(!_variant.name().empty() ? " (" + _variant.name() + "):" : ":") <<
|
||||||
endl;
|
endl;
|
||||||
{
|
{
|
||||||
istringstream stream(_result);
|
istringstream stream(_variant.result);
|
||||||
string line;
|
string line;
|
||||||
while (getline(stream, line))
|
while (getline(stream, line))
|
||||||
_stream << nextIndentLevel << line << endl;
|
_stream << nextIndentLevel << line << endl;
|
||||||
@ -266,14 +240,18 @@ void ASTJSONTest::printSource(ostream& _stream, string const& _linePrefix, bool
|
|||||||
|
|
||||||
void ASTJSONTest::printUpdatedExpectations(std::ostream&, std::string const&) const
|
void ASTJSONTest::printUpdatedExpectations(std::ostream&, std::string const&) const
|
||||||
{
|
{
|
||||||
updateExpectation(m_astFilename, m_result, "");
|
for (TestVariant const& variant: m_variants)
|
||||||
updateExpectation(m_astParseOnlyFilename, m_resultParseOnly, "parseOnly ");
|
updateExpectation(
|
||||||
|
variant.astFilename(),
|
||||||
|
variant.result,
|
||||||
|
variant.name().empty() ? "" : variant.name() + " "
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTJSONTest::updateExpectation(string const& _filename, string const& _expectation, string const& _variation) const
|
void ASTJSONTest::updateExpectation(string const& _filename, string const& _expectation, string const& _variant) const
|
||||||
{
|
{
|
||||||
ofstream file(_filename.c_str());
|
ofstream file(_filename.c_str());
|
||||||
if (!file) BOOST_THROW_EXCEPTION(runtime_error("Cannot write " + _variation + "AST expectation to \"" + _filename + "\"."));
|
if (!file) BOOST_THROW_EXCEPTION(runtime_error("Cannot write " + _variant + "AST expectation to \"" + _filename + "\"."));
|
||||||
file.exceptions(ios::badbit);
|
file.exceptions(ios::badbit);
|
||||||
|
|
||||||
string replacedResult = _expectation;
|
string replacedResult = _expectation;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libsolutil/AnsiColorized.h>
|
#include <libsolutil/AnsiColorized.h>
|
||||||
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
#include <test/TestCase.h>
|
#include <test/TestCase.h>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
@ -37,6 +38,32 @@ namespace solidity::frontend::test
|
|||||||
class ASTJSONTest: public TestCase
|
class ASTJSONTest: public TestCase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct TestVariant
|
||||||
|
{
|
||||||
|
TestVariant(std::string_view _baseName, CompilerStack::State _stopAfter):
|
||||||
|
baseName(_baseName),
|
||||||
|
stopAfter(_stopAfter)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return stopAfter == CompilerStack::State::Parsed ? "parseOnly" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string astFilename() const
|
||||||
|
{
|
||||||
|
return std::string(baseName) +
|
||||||
|
(name().empty() ? "" : "_") +
|
||||||
|
name() +
|
||||||
|
".json";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string baseName;
|
||||||
|
CompilerStack::State stopAfter;
|
||||||
|
std::string result;
|
||||||
|
std::string expectation;
|
||||||
|
};
|
||||||
|
|
||||||
static std::unique_ptr<TestCase> create(Config const& _config)
|
static std::unique_ptr<TestCase> create(Config const& _config)
|
||||||
{
|
{
|
||||||
return std::make_unique<ASTJSONTest>(_config.filename);
|
return std::make_unique<ASTJSONTest>(_config.filename);
|
||||||
@ -49,11 +76,9 @@ public:
|
|||||||
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
||||||
private:
|
private:
|
||||||
bool runTest(
|
bool runTest(
|
||||||
std::string& _expectation,
|
TestVariant& _testVariant,
|
||||||
std::string& _result,
|
|
||||||
std::map<std::string, unsigned> const& _sourceIndices,
|
std::map<std::string, unsigned> const& _sourceIndices,
|
||||||
CompilerStack& _compiler,
|
CompilerStack& _compiler,
|
||||||
std::string const& _variation,
|
|
||||||
std::ostream& _stream,
|
std::ostream& _stream,
|
||||||
std::string const& _linePrefix = "",
|
std::string const& _linePrefix = "",
|
||||||
bool const _formatted = false
|
bool const _formatted = false
|
||||||
@ -61,15 +86,12 @@ private:
|
|||||||
void updateExpectation(
|
void updateExpectation(
|
||||||
std::string const& _filename,
|
std::string const& _filename,
|
||||||
std::string const& _expectation,
|
std::string const& _expectation,
|
||||||
std::string const& _variation
|
std::string const& _variant
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
|
std::vector<TestVariant> m_variants;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> m_sources;
|
std::vector<std::pair<std::string, std::string>> m_sources;
|
||||||
std::string m_expectationParseOnly;
|
|
||||||
std::string m_astFilename;
|
|
||||||
std::string m_astParseOnlyFilename;
|
|
||||||
std::string m_result;
|
|
||||||
std::string m_resultParseOnly;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _inc
|
|||||||
for (auto const& messagePrefix: m_messagesToCut)
|
for (auto const& messagePrefix: m_messagesToCut)
|
||||||
if (currentError->comment()->find(messagePrefix) == 0)
|
if (currentError->comment()->find(messagePrefix) == 0)
|
||||||
{
|
{
|
||||||
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(*currentError);
|
SourceLocation const* location = currentError->sourceLocation();
|
||||||
// sufficient for now, but in future we might clone the error completely, including the secondary location
|
// sufficient for now, but in future we might clone the error completely, including the secondary location
|
||||||
newError = make_shared<Error>(
|
newError = make_shared<Error>(
|
||||||
currentError->errorId(),
|
currentError->errorId(),
|
||||||
|
@ -407,7 +407,10 @@ TestCase::TestResult SemanticTest::runTest(
|
|||||||
if (m_transactionSuccessful == test.call().expectations.failure)
|
if (m_transactionSuccessful == test.call().expectations.failure)
|
||||||
success = false;
|
success = false;
|
||||||
if (success && !checkGasCostExpectation(test, _isYulRun))
|
if (success && !checkGasCostExpectation(test, _isYulRun))
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
m_gasCostFailure = true;
|
m_gasCostFailure = true;
|
||||||
|
}
|
||||||
|
|
||||||
test.setFailure(!m_transactionSuccessful);
|
test.setFailure(!m_transactionSuccessful);
|
||||||
test.setRawBytes(bytes());
|
test.setRawBytes(bytes());
|
||||||
@ -562,14 +565,14 @@ bool SemanticTest::checkGasCostExpectation(TestFunctionCall& io_test, bool _comp
|
|||||||
// We don't check gas if enforce gas cost is not active
|
// We don't check gas if enforce gas cost is not active
|
||||||
// or test is run with abi encoder v1 only
|
// or test is run with abi encoder v1 only
|
||||||
// or gas used less than threshold for enforcing feature
|
// or gas used less than threshold for enforcing feature
|
||||||
|
// or the test has used up all available gas (test will fail anyway)
|
||||||
// or setting is "ir" and it's not included in expectations
|
// or setting is "ir" and it's not included in expectations
|
||||||
// or if the called function is an isoltest builtin e.g. `smokeTest` or `storageEmpty`
|
// or if the called function is an isoltest builtin e.g. `smokeTest` or `storageEmpty`
|
||||||
if (
|
if (
|
||||||
!m_enforceGasCost ||
|
!m_enforceGasCost ||
|
||||||
(
|
m_gasUsed < m_enforceGasCostMinValue ||
|
||||||
(setting == "ir" || m_gasUsed < m_enforceGasCostMinValue || m_gasUsed >= m_gas) &&
|
m_gasUsed >= InitialGas ||
|
||||||
io_test.call().expectations.gasUsed.count(setting) == 0
|
(setting == "ir" && io_test.call().expectations.gasUsed.count(setting) == 0) ||
|
||||||
) ||
|
|
||||||
io_test.call().kind == FunctionCall::Kind::Builtin
|
io_test.call().kind == FunctionCall::Kind::Builtin
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
|
@ -1607,30 +1607,6 @@ BOOST_AUTO_TEST_CASE(library_call_protection)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
library Lib {
|
|
||||||
function x() public view returns (uint) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contract Test {
|
|
||||||
uint t;
|
|
||||||
function f() public returns (uint) {
|
|
||||||
t = 2;
|
|
||||||
return this.g();
|
|
||||||
}
|
|
||||||
function g() public view returns (uint) {
|
|
||||||
return Lib.x();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode, 0, "Lib");
|
|
||||||
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, h160>{{":Lib", m_contractAddress}});
|
|
||||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
|
BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
@ -1786,49 +1762,6 @@ BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(storing_invalid_boolean)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
event Ev(bool);
|
|
||||||
bool public perm;
|
|
||||||
function set() public returns(uint) {
|
|
||||||
bool tmp;
|
|
||||||
assembly {
|
|
||||||
tmp := 5
|
|
||||||
}
|
|
||||||
perm = tmp;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
function ret() public returns(bool) {
|
|
||||||
bool tmp;
|
|
||||||
assembly {
|
|
||||||
tmp := 5
|
|
||||||
}
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
function ev() public returns(uint) {
|
|
||||||
bool tmp;
|
|
||||||
assembly {
|
|
||||||
tmp := 5
|
|
||||||
}
|
|
||||||
emit Ev(tmp);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(callContractFunction("set()"), encodeArgs(1));
|
|
||||||
ABI_CHECK(callContractFunction("perm()"), encodeArgs(1));
|
|
||||||
ABI_CHECK(callContractFunction("ret()"), encodeArgs(1));
|
|
||||||
ABI_CHECK(callContractFunction("ev()"), encodeArgs(1));
|
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
|
||||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
|
||||||
BOOST_CHECK(logData(0) == encodeArgs(1));
|
|
||||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
|
||||||
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Ev(bool)")));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(struct_referencing)
|
BOOST_AUTO_TEST_CASE(struct_referencing)
|
||||||
{
|
{
|
||||||
static char const* sourceCode = R"(
|
static char const* sourceCode = R"(
|
||||||
@ -2059,70 +1992,6 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_abi)
|
|||||||
// ABI_CHECK(callContractFunction("f()"), encodeArgs(5));
|
// ABI_CHECK(callContractFunction("f()"), encodeArgs(5));
|
||||||
//}
|
//}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(packed_storage_structs_delete)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct str { uint8 a; uint16 b; uint8 c; }
|
|
||||||
uint8 x;
|
|
||||||
uint16 y;
|
|
||||||
str data;
|
|
||||||
function test() public returns (uint) {
|
|
||||||
x = 1;
|
|
||||||
y = 2;
|
|
||||||
data.a = 2;
|
|
||||||
data.b = 0xabcd;
|
|
||||||
data.c = 0xfa;
|
|
||||||
if (x != 1 || y != 2 || data.a != 2 || data.b != 0xabcd || data.c != 0xfa)
|
|
||||||
return 2;
|
|
||||||
delete y;
|
|
||||||
delete data.b;
|
|
||||||
if (x != 1 || y != 0 || data.a != 2 || data.b != 0 || data.c != 0xfa)
|
|
||||||
return 3;
|
|
||||||
delete x;
|
|
||||||
delete data;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(callContractFunction("test()"), encodeArgs(1));
|
|
||||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(invalid_enum_logged)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
enum X { A, B }
|
|
||||||
event Log(X);
|
|
||||||
|
|
||||||
function test_log() public returns (uint) {
|
|
||||||
X garbled = X.A;
|
|
||||||
assembly {
|
|
||||||
garbled := 5
|
|
||||||
}
|
|
||||||
emit Log(garbled);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
function test_log_ok() public returns (uint) {
|
|
||||||
X x = X.A;
|
|
||||||
emit Log(x);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(callContractFunction("test_log_ok()"), encodeArgs(u256(1)));
|
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
|
||||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
|
||||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
|
||||||
BOOST_REQUIRE_EQUAL(logTopic(0, 0), util::keccak256(string("Log(uint8)")));
|
|
||||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(0)));
|
|
||||||
|
|
||||||
ABI_CHECK(callContractFunction("test_log()"), panicData(PanicCode::EnumConversionError));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
|
BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
@ -2164,31 +2033,6 @@ BOOST_AUTO_TEST_CASE(failing_send)
|
|||||||
BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20));
|
BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(return_string)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract Main {
|
|
||||||
string public s;
|
|
||||||
function set(string calldata _s) external {
|
|
||||||
s = _s;
|
|
||||||
}
|
|
||||||
function get1() public returns (string memory r) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
function get2() public returns (string memory r) {
|
|
||||||
r = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode, 0, "Main");
|
|
||||||
string s("Julia");
|
|
||||||
bytes args = encodeArgs(u256(0x20), u256(s.length()), s);
|
|
||||||
BOOST_REQUIRE(callContractFunction("set(string)", asString(args)) == encodeArgs());
|
|
||||||
ABI_CHECK(callContractFunction("get1()"), args);
|
|
||||||
ABI_CHECK(callContractFunction("get2()"), args);
|
|
||||||
ABI_CHECK(callContractFunction("s()"), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes)
|
BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
@ -2343,28 +2187,6 @@ BOOST_AUTO_TEST_CASE(return_bytes_internal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(memory_types_initialisation)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract Test {
|
|
||||||
mapping(uint=>uint) data;
|
|
||||||
function stat() public returns (uint[5] memory)
|
|
||||||
{
|
|
||||||
data[2] = 3; // make sure to use some memory
|
|
||||||
}
|
|
||||||
function dyn() public returns (uint[] memory) { stat(); }
|
|
||||||
function nested() public returns (uint[3][] memory) { stat(); }
|
|
||||||
function nestedStat() public returns (uint[3][7] memory) { stat(); }
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode, 0, "Test");
|
|
||||||
|
|
||||||
ABI_CHECK(callContractFunction("stat()"), encodeArgs(vector<u256>(5)));
|
|
||||||
ABI_CHECK(callContractFunction("dyn()"), encodeArgs(u256(0x20), u256(0)));
|
|
||||||
ABI_CHECK(callContractFunction("nested()"), encodeArgs(u256(0x20), u256(0)));
|
|
||||||
ABI_CHECK(callContractFunction("nestedStat()"), encodeArgs(vector<u256>(3 * 7)));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(calldata_struct_short)
|
BOOST_AUTO_TEST_CASE(calldata_struct_short)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
@ -2718,38 +2540,6 @@ BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key)
|
|||||||
), encodeArgs(u256(i - 3)));
|
), encodeArgs(u256(i - 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(constant_string_literal)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract Test {
|
|
||||||
bytes32 constant public b = "abcdefghijklmnopq";
|
|
||||||
string constant public x = "abefghijklmnopqabcdefghijklmnopqabcdefghijklmnopqabca";
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
string memory xx = x;
|
|
||||||
bytes32 bb = b;
|
|
||||||
}
|
|
||||||
function getB() public returns (bytes32) { return b; }
|
|
||||||
function getX() public returns (string memory) { return x; }
|
|
||||||
function getX2() public returns (string memory r) { r = x; }
|
|
||||||
function unused() public returns (uint) {
|
|
||||||
"unusedunusedunusedunusedunusedunusedunusedunusedunusedunusedunusedunused";
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
string longStr = "abefghijklmnopqabcdefghijklmnopqabcdefghijklmnopqabca";
|
|
||||||
string shortStr = "abcdefghijklmnopq";
|
|
||||||
ABI_CHECK(callContractFunction("b()"), encodeArgs(shortStr));
|
|
||||||
ABI_CHECK(callContractFunction("x()"), encodeDyn(longStr));
|
|
||||||
ABI_CHECK(callContractFunction("getB()"), encodeArgs(shortStr));
|
|
||||||
ABI_CHECK(callContractFunction("getX()"), encodeDyn(longStr));
|
|
||||||
ABI_CHECK(callContractFunction("getX2()"), encodeDyn(longStr));
|
|
||||||
ABI_CHECK(callContractFunction("unused()"), encodeArgs(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(library_call)
|
BOOST_AUTO_TEST_CASE(library_call)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -118,9 +118,10 @@ void SyntaxTest::filterObtainedErrors()
|
|||||||
{
|
{
|
||||||
for (auto const& currentError: filterErrors(compiler().errors(), true))
|
for (auto const& currentError: filterErrors(compiler().errors(), true))
|
||||||
{
|
{
|
||||||
int locationStart = -1, locationEnd = -1;
|
int locationStart = -1;
|
||||||
|
int locationEnd = -1;
|
||||||
string sourceName;
|
string sourceName;
|
||||||
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
if (SourceLocation const* location = currentError->sourceLocation())
|
||||||
{
|
{
|
||||||
solAssert(location->sourceName, "");
|
solAssert(location->sourceName, "");
|
||||||
sourceName = *location->sourceName;
|
sourceName = *location->sourceName;
|
||||||
|
@ -11,6 +11,9 @@ contract C {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 1, 2, 3 ->
|
// constructor(): 1, 2, 3 ->
|
||||||
|
// gas irOptimized: 143598
|
||||||
|
// gas legacy: 183490
|
||||||
|
// gas legacyOptimized: 151938
|
||||||
// a(uint256): 0 -> 1
|
// a(uint256): 0 -> 1
|
||||||
// a(uint256): 1 -> 2
|
// a(uint256): 1 -> 2
|
||||||
// a(uint256): 2 -> 3
|
// a(uint256): 2 -> 3
|
||||||
|
@ -11,5 +11,8 @@ contract Creator {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 1, 2, 3, 4 ->
|
// constructor(): 1, 2, 3, 4 ->
|
||||||
|
// gas irOptimized: 132278
|
||||||
|
// gas legacy: 176789
|
||||||
|
// gas legacyOptimized: 129585
|
||||||
// r() -> 4
|
// r() -> 4
|
||||||
// ch() -> 3
|
// ch() -> 3
|
||||||
|
@ -10,5 +10,8 @@ contract Test {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" ->
|
// constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" ->
|
||||||
|
// gas irOptimized: 291443
|
||||||
|
// gas legacy: 309842
|
||||||
|
// gas legacyOptimized: 260801
|
||||||
// m_x() -> 7
|
// m_x() -> 7
|
||||||
// m_s() -> 0x20, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz"
|
// m_s() -> 0x20, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz"
|
||||||
|
@ -19,5 +19,8 @@ contract Main {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): "abc", true
|
// constructor(): "abc", true
|
||||||
|
// gas irOptimized: 112563
|
||||||
|
// gas legacy: 145838
|
||||||
|
// gas legacyOptimized: 104017
|
||||||
// getFlag() -> true
|
// getFlag() -> true
|
||||||
// getName() -> "abc"
|
// getName() -> "abc"
|
||||||
|
@ -12,6 +12,9 @@ contract C {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 1, 2, 3, 4 ->
|
// constructor(): 1, 2, 3, 4 ->
|
||||||
|
// gas irOptimized: 180731
|
||||||
|
// gas legacy: 221377
|
||||||
|
// gas legacyOptimized: 177671
|
||||||
// a() -> 1
|
// a() -> 1
|
||||||
// b(uint256): 0 -> 2
|
// b(uint256): 0 -> 2
|
||||||
// b(uint256): 1 -> 3
|
// b(uint256): 1 -> 3
|
||||||
|
@ -15,4 +15,5 @@ contract B is A {
|
|||||||
// compileViaYul: true
|
// compileViaYul: true
|
||||||
// ----
|
// ----
|
||||||
// constructor() ->
|
// constructor() ->
|
||||||
|
// gas irOptimized: 122233
|
||||||
// y() -> 42
|
// y() -> 42
|
||||||
|
@ -12,4 +12,7 @@ contract B is A {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor() ->
|
// constructor() ->
|
||||||
|
// gas irOptimized: 122233
|
||||||
|
// gas legacy: 135046
|
||||||
|
// gas legacyOptimized: 116176
|
||||||
// y() -> 42
|
// y() -> 42
|
@ -11,5 +11,7 @@ contract C {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 2, 0 ->
|
// constructor(): 2, 0 ->
|
||||||
|
// gas irOptimized: 104227
|
||||||
|
// gas legacy: 117158
|
||||||
// i() -> 2
|
// i() -> 2
|
||||||
// k() -> 0
|
// k() -> 0
|
||||||
|
@ -23,6 +23,9 @@ contract D is B, C {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 2, 0 ->
|
// constructor(): 2, 0 ->
|
||||||
|
// gas irOptimized: 159542
|
||||||
|
// gas legacy: 170665
|
||||||
|
// gas legacyOptimized: 145396
|
||||||
// i() -> 2
|
// i() -> 2
|
||||||
// j() -> 2
|
// j() -> 2
|
||||||
// k() -> 1
|
// k() -> 1
|
||||||
|
@ -14,5 +14,8 @@ contract D is C {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 2, 0 ->
|
// constructor(): 2, 0 ->
|
||||||
|
// gas irOptimized: 124844
|
||||||
|
// gas legacy: 139250
|
||||||
|
// gas legacyOptimized: 119367
|
||||||
// i() -> 2
|
// i() -> 2
|
||||||
// k() -> 1
|
// k() -> 1
|
||||||
|
24
test/libsolidity/semanticTests/enums/invalid_enum_logged.sol
Normal file
24
test/libsolidity/semanticTests/enums/invalid_enum_logged.sol
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
contract C {
|
||||||
|
enum X { A, B }
|
||||||
|
event Log(X);
|
||||||
|
|
||||||
|
function test_log() public returns (uint) {
|
||||||
|
X garbled = X.A;
|
||||||
|
assembly {
|
||||||
|
garbled := 5
|
||||||
|
}
|
||||||
|
emit Log(garbled);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
function test_log_ok() public returns (uint) {
|
||||||
|
X x = X.A;
|
||||||
|
emit Log(x);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test_log_ok() -> 1
|
||||||
|
// ~ emit Log(uint8): 0x00
|
||||||
|
// test_log() -> FAILURE, hex"4e487b71", 0x21
|
@ -17,6 +17,8 @@ contract C {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor() ->
|
// constructor() ->
|
||||||
// gas legacy: 249112
|
// gas irOptimized: 177344
|
||||||
|
// gas legacy: 250376
|
||||||
|
// gas legacyOptimized: 174522
|
||||||
// deposit(bytes32), 18 wei: 0x1234 ->
|
// deposit(bytes32), 18 wei: 0x1234 ->
|
||||||
// ~ emit Deposit(address,bytes32,uint256) from 0xf01f7809444bd9a93a854361c6fae3f23d9e23db: #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b, #0x1234, 0x00
|
// ~ emit Deposit(address,bytes32,uint256) from 0xf01f7809444bd9a93a854361c6fae3f23d9e23db: #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b, #0x1234, 0x00
|
||||||
|
@ -20,4 +20,4 @@ contract C {
|
|||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// ~ emit E((uint8,int16),(uint8,int16)): #0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5, 0x00, 0x00
|
// ~ emit E((uint8,int16),(uint8,int16)): #0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5, 0x00, 0x00
|
||||||
// gas legacy: 150662
|
// gas legacy: 150602
|
||||||
|
@ -76,7 +76,7 @@ contract FixedFeeRegistrar is Registrar {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// gas irOptimized: 425623
|
// gas irOptimized: 426283
|
||||||
// gas legacy: 936897
|
// gas legacy: 936897
|
||||||
// gas legacyOptimized: 490983
|
// gas legacyOptimized: 490983
|
||||||
// reserve(string), 69 ether: 0x20, 3, "abc" ->
|
// reserve(string), 69 ether: 0x20, 3, "abc" ->
|
||||||
|
@ -178,9 +178,9 @@ contract DepositContract is IDepositContract, ERC165 {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// gas irOptimized: 1558013
|
// gas irOptimized: 1558001
|
||||||
// gas legacy: 2580394
|
// gas legacy: 2436584
|
||||||
// gas legacyOptimized: 1775403
|
// gas legacyOptimized: 1776483
|
||||||
// supportsInterface(bytes4): 0x0 -> 0
|
// supportsInterface(bytes4): 0x0 -> 0
|
||||||
// supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 #
|
// supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 #
|
||||||
// supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id #
|
// supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id #
|
||||||
|
@ -50,8 +50,8 @@ contract test {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// gas irOptimized: 1924584
|
// gas irOptimized: 1924392
|
||||||
// gas legacy: 2602700
|
// gas legacy: 2480887
|
||||||
// gas legacyOptimized: 1874490
|
// gas legacyOptimized: 1874490
|
||||||
// div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328
|
// div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328
|
||||||
// gas irOptimized: 22137
|
// gas irOptimized: 22137
|
||||||
|
@ -51,7 +51,7 @@ contract test {
|
|||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// gas irOptimized: 1778342
|
// gas irOptimized: 1778342
|
||||||
// gas legacy: 2356230
|
// gas legacy: 2250130
|
||||||
// gas legacyOptimized: 1746528
|
// gas legacyOptimized: 1746528
|
||||||
// div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328
|
// div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328
|
||||||
// gas irOptimized: 22004
|
// gas irOptimized: 22004
|
||||||
|
@ -36,7 +36,7 @@ contract test {
|
|||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// gas irOptimized: 465357
|
// gas irOptimized: 465357
|
||||||
// gas legacy: 733634
|
// gas legacy: 672749
|
||||||
// gas legacyOptimized: 479606
|
// gas legacyOptimized: 479606
|
||||||
// prb_pi() -> 3141592656369545286
|
// prb_pi() -> 3141592656369545286
|
||||||
// gas irOptimized: 57478
|
// gas irOptimized: 57478
|
||||||
|
@ -52,7 +52,7 @@ contract test {
|
|||||||
// ----
|
// ----
|
||||||
// constructor()
|
// constructor()
|
||||||
// gas irOptimized: 702619
|
// gas irOptimized: 702619
|
||||||
// gas legacy: 1188228
|
// gas legacy: 1130761
|
||||||
// gas legacyOptimized: 750416
|
// gas legacyOptimized: 750416
|
||||||
// toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0
|
// toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0
|
||||||
// gas irOptimized: 22660
|
// gas irOptimized: 22660
|
||||||
|
@ -17,4 +17,7 @@ contract D {
|
|||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// constructor(): 2 ->
|
// constructor(): 2 ->
|
||||||
|
// gas irOptimized: 200295
|
||||||
|
// gas legacy: 245842
|
||||||
|
// gas legacyOptimized: 195676
|
||||||
// f() -> 2
|
// f() -> 2
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user