mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
6b3171c38b
@ -598,7 +598,7 @@ jobs:
|
||||
|
||||
b_ems:
|
||||
docker:
|
||||
- image: ethereum/solidity-buildpack-deps:emsdk-1.39.15-1
|
||||
- image: ethereum/solidity-buildpack-deps:emsdk-1.39.15-2
|
||||
environment:
|
||||
TERM: xterm
|
||||
steps:
|
||||
|
@ -26,11 +26,9 @@
|
||||
# contains a Makefile in the docker/ subdirectory that can be used to create the
|
||||
# required base image using:
|
||||
#
|
||||
# make version=1.39.15-fastcomp build
|
||||
# make version=1.39.15 build
|
||||
#
|
||||
# TODO: switch to the upstream backend by removing "-fastcomp".
|
||||
#
|
||||
FROM emscripten/emsdk:1.39.15-fastcomp AS base
|
||||
FROM emscripten/emsdk:1.39.15 AS base
|
||||
|
||||
ADD emscripten.jam /usr/src
|
||||
RUN set -ex; \
|
||||
@ -47,6 +45,7 @@ RUN set -ex; \
|
||||
-DZ3_BUILD_TEST_EXECUTABLES=OFF \
|
||||
-DZ3_BUILD_EXECUTABLE=OFF \
|
||||
-DZ3_SINGLE_THREADED=ON \
|
||||
-DCMAKE_CXX_FLAGS="-s DISABLE_EXCEPTION_CATCHING=0" \
|
||||
..; \
|
||||
make; make install; \
|
||||
rm -r /usr/src/z3; \
|
||||
@ -61,6 +60,6 @@ RUN set -ex; \
|
||||
echo "using emscripten : : em++ ;" >> project-config.jam ; \
|
||||
./b2 toolset=emscripten link=static variant=release threading=single runtime-link=static \
|
||||
--with-system --with-filesystem --with-test --with-program_options \
|
||||
cxxflags="-Wno-unused-local-typedef -Wno-variadic-macros -Wno-c99-extensions -Wno-all" \
|
||||
cxxflags="-s DISABLE_EXCEPTION_CATCHING=0 -Wno-unused-local-typedef -Wno-variadic-macros -Wno-c99-extensions -Wno-all" \
|
||||
--prefix=/emsdk/emscripten/sdk/system install; \
|
||||
rm -r /usr/src/boost_1_73_0
|
||||
|
43
Changelog.md
43
Changelog.md
@ -19,39 +19,56 @@ Bugfixes:
|
||||
* NatSpec: Constructors and functions have consistent userdoc output.
|
||||
|
||||
|
||||
### 0.6.9 (unreleased)
|
||||
### 0.6.10 (unreleased)
|
||||
|
||||
Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Yul: Raise warning for switch statements that only have a default and no other cases.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* SMTChecker: Fix internal error when encoding tuples of tuples.
|
||||
* SMTChecker: Fix aliasing soundness after pushing to an array pointer.
|
||||
|
||||
|
||||
### 0.6.9 (2020-06-04)
|
||||
|
||||
Language Features:
|
||||
* Permit calldata location for all variables.
|
||||
* NatSpec: Support NatSpec comments on state variables.
|
||||
* Yul: EVM instruction `pc()` is marked deprecated and will be removed in the next breaking release.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Code Generator: Do not introduce new source references for small internal routines.
|
||||
* Build system: Update the soljson.js build to emscripten 1.39.15 and boost 1.73.0 and include Z3 for integrated SMTChecker support without the callback mechanism.
|
||||
* Commandline Interface: Adds new option ``--base-path PATH`` to use the given path as the root of the source tree instead of the root of the filesystem.
|
||||
* Build system: Switch the emscripten build from the fastcomp backend to the upstream backend.
|
||||
* Code Generator: Do not introduce new internal source references for small compiler routines.
|
||||
* Commandline Interface: Adds new option ``--base-path PATH`` to use the given path as the root of the source tree (defaults to the root of the filesystem).
|
||||
* SMTChecker: Support array ``length``.
|
||||
* SMTChecker: Support array ``push`` and ``pop``.
|
||||
* SMTChecker: General support to BitVectors and the bitwise ``and`` operator.
|
||||
* Add support for natspec comments on state variables.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
|
||||
* Commandline Interface: Fix internal error when using ``--assemble`` or ``--yul`` options with ``--machine ewasm`` but without specifying ``--yul-dialect``.
|
||||
* NatSpec: DocString block is terminated when encountering an empty line.
|
||||
* Optimizer: Fixed a bug in BlockDeDuplicator.
|
||||
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
|
||||
* SMTChecker: Fix internal error on try/catch clauses with parameters.
|
||||
* SMTChecker: Fix internal error when applying arithmetic operators to fixed point variables.
|
||||
* SMTChecker: Fix internal error when assigning to index access inside branches.
|
||||
* SMTChecker: Fix internal error when short circuiting Boolean expressions with function calls in state variable initialization.
|
||||
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
|
||||
* Type Checker: Disallow inline arrays of non-nameable types.
|
||||
* Type Checker: Disallow usage of override with non-public state variables.
|
||||
* Type Checker: Fix internal compiler error when accessing members of array slices.
|
||||
* Type Checker: Fix internal compiler error when forward referencing non-literal constants from inline assembly.
|
||||
* Type Checker: Fix internal compiler error when trying to decode too large static arrays.
|
||||
* Type Checker: Fix wrong compiler error when referencing an overridden function without calling it.
|
||||
* Type Checker: Fix internal compiler error when forward referencing non-literal constants from inline assembly.
|
||||
* Type Checker: Disallow usage of override with non-public state variables.
|
||||
* NatSpec: DocString block is terminated when encountering an empty line.
|
||||
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
|
||||
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
|
||||
* SMTChecker: Fix internal error when applying arithmetic operators to fixed point variables.
|
||||
* SMTChecker: Fix internal error when short circuiting Boolean expressions with function calls in state variable initialization.
|
||||
* SMTChecker: Fix internal error when assigning to index access inside branches.
|
||||
* SMTChecker: Fix internal error on try/catch clauses with parameters.
|
||||
|
||||
|
||||
### 0.6.8 (2020-05-14)
|
||||
|
||||
|
@ -6,9 +6,8 @@
|
||||
- [ ] Readthedocs account, access to the Solidity project
|
||||
- [ ] Write access to https://github.com/ethereum/homebrew-ethereum
|
||||
|
||||
### Pre-release
|
||||
- [ ] Ensure that a Github project exists for the release.
|
||||
- [ ] Check that all issues and pull requests from the Github project to be released are merged to ``develop``.
|
||||
### Blog Post
|
||||
- [ ] Create a post on https://github.com/ethereum/solidity-blog and explain some of the new features or concepts.
|
||||
|
||||
### Changelog
|
||||
- [ ] Sort the changelog entries alphabetically and correct any errors you notice.
|
||||
@ -33,8 +32,9 @@
|
||||
- [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` and ``Xenial`` while selecting ``Copy existing binaries``.
|
||||
- [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh v0.x.x``).
|
||||
|
||||
### Homebrew
|
||||
### Homebrew and MacOS
|
||||
- [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb
|
||||
- [ ] Take the binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``.
|
||||
|
||||
### Documentation
|
||||
- [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` on the bottom of the page and click `BUILD`)
|
||||
|
@ -16,9 +16,11 @@
|
||||
|
||||
include(EthCheckCXXCompilerFlag)
|
||||
|
||||
eth_add_cxx_compiler_flag_if_supported(-fstack-protector-strong have_stack_protector_strong_support)
|
||||
if(NOT have_stack_protector_strong_support)
|
||||
eth_add_cxx_compiler_flag_if_supported(-fstack-protector)
|
||||
if(NOT EMSCRIPTEN)
|
||||
eth_add_cxx_compiler_flag_if_supported(-fstack-protector-strong have_stack_protector_strong_support)
|
||||
if(NOT have_stack_protector_strong_support)
|
||||
eth_add_cxx_compiler_flag_if_supported(-fstack-protector)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
eth_add_cxx_compiler_flag_if_supported(-Wimplicit-fallthrough)
|
||||
@ -109,15 +111,13 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
|
||||
# Re-enable exception catching (optimisations above -O1 disable it)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0")
|
||||
# Remove any code related to exit (such as atexit)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_EXIT_RUNTIME=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXIT_RUNTIME=0")
|
||||
# Remove any code related to filesystem access
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_FILESYSTEM=1")
|
||||
# Remove variables even if it needs to be duplicated (can improve speed at the cost of size)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s AGGRESSIVE_VARIABLE_ELIMINATION=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s FILESYSTEM=0")
|
||||
# Allow memory growth, but disable some optimisations
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
|
||||
# Disable eval()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_DYNAMIC_EXECUTION=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s DYNAMIC_EXECUTION=0")
|
||||
# Disable greedy exception catcher
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NODEJS_CATCH_EXIT=0")
|
||||
# Abort if linking results in any undefined symbols
|
||||
|
@ -42,7 +42,8 @@ For most of the topics the compiler will provide suggestions.
|
||||
storage arrays.
|
||||
|
||||
* The new keyword ``abstract`` can be used to mark contracts as abstract. It has to be used
|
||||
if a contract does not implement all its functions.
|
||||
if a contract does not implement all its functions. Abstract contracts cannot be created using the ``new`` operator,
|
||||
and it is not possible to generate bytecode for them during compilation.
|
||||
|
||||
* Libraries have to implement all their functions, not only the internal ones.
|
||||
|
||||
|
@ -124,7 +124,11 @@ userDefinedTypeName
|
||||
: identifier ( '.' identifier )* ;
|
||||
|
||||
mapping
|
||||
: 'mapping' '(' (elementaryTypeName | userDefinedTypeName) '=>' typeName ')' ;
|
||||
: 'mapping' '(' mappingKey '=>' typeName ')' ;
|
||||
|
||||
mappingKey
|
||||
: elementaryTypeName
|
||||
| userDefinedTypeName ;
|
||||
|
||||
functionTypeName
|
||||
: 'function' parameterList modifierList returnParameters? ;
|
||||
@ -470,7 +474,7 @@ SingleQuotedStringCharacter
|
||||
: ~['\r\n\\] | ('\\' .) ;
|
||||
|
||||
VersionLiteral
|
||||
: [0-9]+ '.' [0-9]+ ('.' [0-9]+)? ;
|
||||
: [0-9]+ ( '.' [0-9]+ ('.' [0-9]+)? )? ;
|
||||
|
||||
WS
|
||||
: [ \t\r\n\u000C]+ -> skip ;
|
||||
|
@ -24,7 +24,7 @@ Function Selector
|
||||
=================
|
||||
|
||||
The first four bytes of the call data for a function call specifies the function to be called. It is the
|
||||
first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3) hash of the signature of
|
||||
first (left, high-order in big-endian) four bytes of the Keccak-256 hash of the signature of
|
||||
the function. The signature is defined as the canonical expression of the basic prototype without data
|
||||
location specifier, i.e.
|
||||
the function name with the parenthesised list of parameter types. Parameter types are split by a single
|
||||
|
@ -1163,5 +1163,9 @@
|
||||
"0.6.8": {
|
||||
"bugs": [],
|
||||
"released": "2020-05-14"
|
||||
},
|
||||
"0.6.9": {
|
||||
"bugs": [],
|
||||
"released": "2020-06-04"
|
||||
}
|
||||
}
|
@ -194,10 +194,10 @@ not known in the context of the class where it is used,
|
||||
although its type is known. This is similar for ordinary
|
||||
virtual method lookup.
|
||||
|
||||
.. _function-overriding:
|
||||
|
||||
.. index:: ! overriding;function
|
||||
|
||||
.. _function-overriding:
|
||||
|
||||
Function Overriding
|
||||
===================
|
||||
|
||||
@ -317,10 +317,10 @@ of the variable:
|
||||
While public state variables can override external functions, they themselves cannot
|
||||
be overridden.
|
||||
|
||||
.. _modifier-overriding:
|
||||
|
||||
.. index:: ! overriding;modifier
|
||||
|
||||
.. _modifier-overriding:
|
||||
|
||||
Modifier Overriding
|
||||
===================
|
||||
|
||||
|
@ -82,7 +82,7 @@ TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const
|
||||
|
||||
bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
{
|
||||
m_scope = &_contract;
|
||||
m_currentContract = &_contract;
|
||||
|
||||
ASTNode::listAccept(_contract.baseContracts(), *this);
|
||||
|
||||
@ -266,7 +266,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
|
||||
solAssert(base, "Base contract not available.");
|
||||
|
||||
if (m_scope->isInterface() && !base->isInterface())
|
||||
if (m_currentContract->isInterface() && !base->isInterface())
|
||||
m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces.");
|
||||
|
||||
if (base->isLibrary())
|
||||
@ -328,8 +328,6 @@ void TypeChecker::endVisit(ModifierDefinition const& _modifier)
|
||||
|
||||
bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
bool isLibraryFunction = _function.inContractKind() == ContractKind::Library;
|
||||
|
||||
if (_function.markedVirtual())
|
||||
{
|
||||
if (_function.annotation().contract->isInterface())
|
||||
@ -342,7 +340,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
|
||||
if (_function.isPayable())
|
||||
{
|
||||
if (isLibraryFunction)
|
||||
if (_function.libraryFunction())
|
||||
m_errorReporter.typeError(7708_error, _function.location(), "Library functions cannot be payable.");
|
||||
if (_function.isOrdinary() && !_function.isPartOfExternalInterface())
|
||||
m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable.");
|
||||
@ -352,15 +350,13 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
if (var.referenceLocation() != VariableDeclaration::Location::Storage)
|
||||
{
|
||||
if (!isLibraryFunction && _function.isPublic())
|
||||
if (!_function.libraryFunction() && _function.isPublic())
|
||||
m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions.");
|
||||
else
|
||||
m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." );
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(isLibraryFunction || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
|
||||
}
|
||||
solAssert(_function.libraryFunction() || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -368,7 +364,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage.");
|
||||
if (_function.isPublic())
|
||||
{
|
||||
auto iType = type(var)->interfaceType(isLibraryFunction);
|
||||
auto iType = type(var)->interfaceType(_function.libraryFunction());
|
||||
|
||||
if (!iType)
|
||||
{
|
||||
@ -380,7 +376,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (
|
||||
_function.isPublic() &&
|
||||
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!typeSupportedByOldABIEncoder(*type(var), isLibraryFunction)
|
||||
!typeSupportedByOldABIEncoder(*type(var), _function.libraryFunction())
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
4957_error,
|
||||
@ -419,7 +415,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
else
|
||||
modifiers.insert(decl);
|
||||
}
|
||||
if (m_scope->isInterface())
|
||||
if (m_currentContract->isInterface())
|
||||
{
|
||||
if (_function.isImplemented())
|
||||
m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation.");
|
||||
@ -430,14 +426,14 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (_function.isConstructor())
|
||||
m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces.");
|
||||
}
|
||||
else if (m_scope->contractKind() == ContractKind::Library)
|
||||
else if (m_currentContract->contractKind() == ContractKind::Library)
|
||||
if (_function.isConstructor())
|
||||
m_errorReporter.typeError(7634_error, _function.location(), "Constructor cannot be defined in libraries.");
|
||||
if (_function.isImplemented())
|
||||
_function.body().accept(*this);
|
||||
else if (_function.isConstructor())
|
||||
m_errorReporter.typeError(5700_error, _function.location(), "Constructor must be implemented if declared.");
|
||||
else if (isLibraryFunction)
|
||||
else if (_function.libraryFunction())
|
||||
m_errorReporter.typeError(9231_error, _function.location(), "Library functions must be implemented if declared.");
|
||||
else if (!_function.virtualSemantics())
|
||||
m_errorReporter.typeError(5424_error, _function.location(), "Functions without implementation must be marked virtual.");
|
||||
@ -1796,7 +1792,7 @@ void TypeChecker::typeCheckFunctionCall(
|
||||
if (_functionType->kind() == FunctionType::Kind::Declaration)
|
||||
{
|
||||
if (
|
||||
m_scope->derivesFrom(*_functionType->declaration().annotation().contract) &&
|
||||
m_currentContract->derivesFrom(*_functionType->declaration().annotation().contract) &&
|
||||
!dynamic_cast<FunctionDefinition const&>(_functionType->declaration()).isImplemented()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
@ -1832,7 +1828,7 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(_function.isFallback(), "");
|
||||
|
||||
if (_function.inContractKind() == ContractKind::Library)
|
||||
if (_function.libraryFunction())
|
||||
m_errorReporter.typeError(5982_error, _function.location(), "Libraries cannot have fallback functions.");
|
||||
if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable)
|
||||
m_errorReporter.typeError(
|
||||
@ -1859,7 +1855,7 @@ void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(_function.isReceive(), "");
|
||||
|
||||
if (_function.inContractKind() == ContractKind::Library)
|
||||
if (_function.libraryFunction())
|
||||
m_errorReporter.typeError(4549_error, _function.location(), "Libraries cannot have receive ether functions.");
|
||||
|
||||
if (_function.stateMutability() != StateMutability::Payable)
|
||||
@ -1918,7 +1914,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
|
||||
bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked;
|
||||
solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding");
|
||||
|
||||
bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count(
|
||||
bool const abiEncoderV2 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
|
||||
ExperimentalFeature::ABIEncoderV2
|
||||
);
|
||||
|
||||
@ -2318,7 +2314,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::ABIDecode:
|
||||
{
|
||||
bool const abiEncoderV2 =
|
||||
m_scope->sourceUnit().annotation().experimentalFeatures.count(
|
||||
m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
|
||||
ExperimentalFeature::ABIEncoderV2
|
||||
);
|
||||
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
|
||||
@ -2514,13 +2510,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
if (contract->abstract())
|
||||
m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract.");
|
||||
|
||||
solAssert(!!m_scope, "");
|
||||
m_scope->annotation().contractDependencies.insert(contract);
|
||||
solAssert(!!m_currentContract, "");
|
||||
m_currentContract->annotation().contractDependencies.insert(contract);
|
||||
solAssert(
|
||||
!contract->annotation().linearizedBaseContracts.empty(),
|
||||
"Linearized base contracts not yet available."
|
||||
);
|
||||
if (contractDependenciesAreCyclic(*m_scope))
|
||||
if (contractDependenciesAreCyclic(*m_currentContract))
|
||||
m_errorReporter.typeError(
|
||||
4579_error,
|
||||
_newExpression.location(),
|
||||
@ -2567,7 +2563,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
|
||||
// Retrieve the types of the arguments if this is used to call a function.
|
||||
auto const& arguments = _memberAccess.annotation().arguments;
|
||||
MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName);
|
||||
MemberList::MemberMap possibleMembers = exprType->members(m_currentContract).membersByName(memberName);
|
||||
size_t const initialMemberCount = possibleMembers.size();
|
||||
if (initialMemberCount > 1 && arguments)
|
||||
{
|
||||
@ -2593,7 +2589,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
DataLocation::Storage,
|
||||
exprType
|
||||
);
|
||||
if (!storageType->members(m_scope).membersByName(memberName).empty())
|
||||
if (!storageType->members(m_currentContract).membersByName(memberName).empty())
|
||||
m_errorReporter.fatalTypeError(
|
||||
4994_error,
|
||||
_memberAccess.location(),
|
||||
@ -2749,7 +2745,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
annotation.isPure = true;
|
||||
ContractType const& accessedContractType = dynamic_cast<ContractType const&>(*magicType->typeArgument());
|
||||
m_scope->annotation().contractDependencies.insert(&accessedContractType.contractDefinition());
|
||||
m_currentContract->annotation().contractDependencies.insert(&accessedContractType.contractDefinition());
|
||||
|
||||
if (
|
||||
memberName == "runtimeCode" &&
|
||||
@ -2761,7 +2757,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
"\"runtimeCode\" is not available for contracts containing immutable variables."
|
||||
);
|
||||
|
||||
if (contractDependenciesAreCyclic(*m_scope))
|
||||
if (contractDependenciesAreCyclic(*m_currentContract))
|
||||
m_errorReporter.typeError(
|
||||
4224_error,
|
||||
_memberAccess.location(),
|
||||
|
@ -165,7 +165,7 @@ private:
|
||||
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
|
||||
void requireLValue(Expression const& _expression, bool _ordinaryAssignment);
|
||||
|
||||
ContractDefinition const* m_scope = nullptr;
|
||||
ContractDefinition const* m_currentContract = nullptr;
|
||||
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
|
||||
|
@ -276,7 +276,7 @@ void ViewPureChecker::reportMutability(
|
||||
{
|
||||
// We do not warn for library functions because they cannot be payable anyway.
|
||||
// Also internal functions should be allowed to use `msg.value`.
|
||||
if (m_currentFunction->isPublic() && m_currentFunction->inContractKind() != ContractKind::Library)
|
||||
if (m_currentFunction->isPublic() && !m_currentFunction->libraryFunction())
|
||||
{
|
||||
if (_nestedLocation)
|
||||
m_errorReporter.typeError(
|
||||
|
@ -287,11 +287,11 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const
|
||||
return initAnnotation<TypeDeclarationAnnotation>();
|
||||
}
|
||||
|
||||
ContractKind FunctionDefinition::inContractKind() const
|
||||
bool FunctionDefinition::libraryFunction() const
|
||||
{
|
||||
auto contractDef = dynamic_cast<ContractDefinition const*>(scope());
|
||||
solAssert(contractDef, "Enclosing Scope of FunctionDefinition was not set.");
|
||||
return contractDef->contractKind();
|
||||
if (auto const* contractDef = dynamic_cast<ContractDefinition const*>(scope()))
|
||||
return contractDef->isLibrary();
|
||||
return false;
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
||||
|
@ -799,6 +799,7 @@ public:
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
StateMutability stateMutability() const { return m_stateMutability; }
|
||||
bool libraryFunction() const;
|
||||
bool isOrdinary() const { return m_kind == Token::Function; }
|
||||
bool isConstructor() const { return m_kind == Token::Constructor; }
|
||||
bool isFallback() const { return m_kind == Token::Fallback; }
|
||||
@ -825,8 +826,6 @@ public:
|
||||
/// @returns the external identifier of this function (the hash of the signature) as a hex string.
|
||||
std::string externalIdentifierHex() const;
|
||||
|
||||
ContractKind inContractKind() const;
|
||||
|
||||
TypePointer type() const override;
|
||||
TypePointer typeViaContractName() const override;
|
||||
|
||||
|
@ -1730,7 +1730,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
|
||||
setLValue(_indexAccess, IRLValue{
|
||||
*arrayType.baseType(),
|
||||
IRLValue::Memory{memAddress}
|
||||
IRLValue::Memory{memAddress, arrayType.isByteArray()}
|
||||
});
|
||||
break;
|
||||
}
|
||||
@ -1763,7 +1763,23 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
}
|
||||
}
|
||||
else if (baseType.category() == Type::Category::FixedBytes)
|
||||
solUnimplementedAssert(false, "");
|
||||
{
|
||||
auto const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
|
||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||
|
||||
IRVariable index{m_context.newYulVariable(), *TypeProvider::uint256()};
|
||||
define(index, *_indexAccess.indexExpression());
|
||||
m_code << Whiskers(R"(
|
||||
if iszero(lt(<index>, <length>)) { invalid() }
|
||||
let <result> := <shl248>(byte(<index>, <array>))
|
||||
)")
|
||||
("index", index.name())
|
||||
("length", to_string(fixedBytesType.numBytes()))
|
||||
("array", IRVariable(_indexAccess.baseExpression()).name())
|
||||
("shl248", m_utils.shiftLeftFunction(256 - 8))
|
||||
("result", IRVariable(_indexAccess).name())
|
||||
.render();
|
||||
}
|
||||
else if (baseType.category() == Type::Category::TypeType)
|
||||
{
|
||||
solAssert(baseType.sizeOnStack() == 0, "");
|
||||
|
@ -604,7 +604,11 @@ void BMC::checkUnderflow(BMCVerificationTarget& _target, smtutil::Expression con
|
||||
_target.type == VerificationTarget::Type::UnderOverflow,
|
||||
""
|
||||
);
|
||||
auto intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type);
|
||||
IntegerType const* intType = nullptr;
|
||||
if (auto const* type = dynamic_cast<IntegerType const*>(_target.expression->annotation().type))
|
||||
intType = type;
|
||||
else
|
||||
intType = TypeProvider::uint256();
|
||||
solAssert(intType, "");
|
||||
checkCondition(
|
||||
_target.constraints && _constraints && _target.value < smt::minValue(*intType),
|
||||
@ -626,7 +630,12 @@ void BMC::checkOverflow(BMCVerificationTarget& _target, smtutil::Expression cons
|
||||
_target.type == VerificationTarget::Type::UnderOverflow,
|
||||
""
|
||||
);
|
||||
auto intType = dynamic_cast<IntegerType const*>(_target.expression->annotation().type);
|
||||
IntegerType const* intType = nullptr;
|
||||
if (auto const* type = dynamic_cast<IntegerType const*>(_target.expression->annotation().type))
|
||||
intType = type;
|
||||
else
|
||||
intType = TypeProvider::uint256();
|
||||
|
||||
solAssert(intType, "");
|
||||
checkCondition(
|
||||
_target.constraints && _constraints && _target.value > smt::maxValue(*intType),
|
||||
|
@ -385,44 +385,22 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& type = _assignment.annotation().type;
|
||||
vector<smtutil::Expression> rightArguments;
|
||||
if (auto const* tupleTypeRight = dynamic_cast<TupleType const*>(_assignment.rightHandSide().annotation().type))
|
||||
{
|
||||
auto symbTupleLeft = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_assignment.leftHandSide()));
|
||||
solAssert(symbTupleLeft, "");
|
||||
auto symbTupleRight = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_assignment.rightHandSide()));
|
||||
solAssert(symbTupleRight, "");
|
||||
|
||||
auto const& leftComponents = symbTupleLeft->components();
|
||||
auto const& rightComponents = symbTupleRight->components();
|
||||
solAssert(leftComponents.size() == rightComponents.size(), "");
|
||||
|
||||
auto tupleTypeLeft = dynamic_cast<TupleType const*>(_assignment.leftHandSide().annotation().type);
|
||||
solAssert(tupleTypeLeft, "");
|
||||
solAssert(tupleTypeLeft->components().size() == leftComponents.size(), "");
|
||||
auto const& typesLeft = tupleTypeLeft->components();
|
||||
|
||||
solAssert(tupleTypeRight->components().size() == rightComponents.size(), "");
|
||||
auto const& typesRight = tupleTypeRight->components();
|
||||
|
||||
for (unsigned i = 0; i < rightComponents.size(); ++i)
|
||||
rightArguments.push_back(symbTupleRight->component(i, typesRight.at(i), typesLeft.at(i)));
|
||||
}
|
||||
if (dynamic_cast<TupleType const*>(_assignment.rightHandSide().annotation().type))
|
||||
tupleAssignment(_assignment.leftHandSide(), _assignment.rightHandSide());
|
||||
else
|
||||
{
|
||||
auto const& type = _assignment.annotation().type;
|
||||
auto rightHandSide = compoundOps.count(op) ?
|
||||
compoundAssignment(_assignment) :
|
||||
expr(_assignment.rightHandSide(), type);
|
||||
defineExpr(_assignment, rightHandSide);
|
||||
rightArguments.push_back(expr(_assignment, type));
|
||||
assignment(
|
||||
_assignment.leftHandSide(),
|
||||
expr(_assignment, type),
|
||||
type,
|
||||
_assignment.location()
|
||||
);
|
||||
}
|
||||
assignment(
|
||||
_assignment.leftHandSide(),
|
||||
rightArguments,
|
||||
type,
|
||||
_assignment.location()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1023,38 +1001,7 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smtutil::Expressi
|
||||
solAssert(varDecl, "");
|
||||
|
||||
if (varDecl->hasReferenceOrMappingType())
|
||||
m_context.resetVariables([&](VariableDeclaration const& _var) {
|
||||
if (_var == *varDecl)
|
||||
return false;
|
||||
|
||||
// If both are state variables no need to clear knowledge.
|
||||
if (_var.isStateVariable() && varDecl->isStateVariable())
|
||||
return false;
|
||||
|
||||
TypePointer prefix = _var.type();
|
||||
TypePointer originalType = typeWithoutPointer(varDecl->type());
|
||||
while (
|
||||
prefix->category() == Type::Category::Mapping ||
|
||||
prefix->category() == Type::Category::Array
|
||||
)
|
||||
{
|
||||
if (*originalType == *typeWithoutPointer(prefix))
|
||||
return true;
|
||||
if (prefix->category() == Type::Category::Mapping)
|
||||
{
|
||||
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
|
||||
solAssert(mapPrefix, "");
|
||||
prefix = mapPrefix->valueType();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
|
||||
solAssert(arrayPrefix, "");
|
||||
prefix = arrayPrefix->baseType();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
resetReferences(*varDecl);
|
||||
|
||||
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.variable(*varDecl));
|
||||
smtutil::Expression store = smtutil::Expression::store(
|
||||
@ -1160,6 +1107,8 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression
|
||||
{
|
||||
auto varDecl = identifierToVariable(*id);
|
||||
solAssert(varDecl, "");
|
||||
if (varDecl->hasReferenceOrMappingType())
|
||||
resetReferences(*varDecl);
|
||||
m_context.addAssertion(m_context.newValue(*varDecl) == _array);
|
||||
}
|
||||
else if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(&_expr))
|
||||
@ -1213,7 +1162,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op)
|
||||
{
|
||||
auto type = _op.annotation().commonType;
|
||||
solAssert(type, "");
|
||||
if (type->category() == Type::Category::Integer)
|
||||
if (type->category() == Type::Category::Integer || type->category() == Type::Category::FixedPoint)
|
||||
{
|
||||
switch (_op.getOperator())
|
||||
{
|
||||
@ -1266,13 +1215,21 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
};
|
||||
solAssert(validOperators.count(_op), "");
|
||||
solAssert(_commonType, "");
|
||||
solAssert(_commonType->category() == Type::Category::Integer, "");
|
||||
solAssert(
|
||||
_commonType->category() == Type::Category::Integer || _commonType->category() == Type::Category::FixedPoint,
|
||||
""
|
||||
);
|
||||
|
||||
IntegerType const* intType = nullptr;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(_commonType))
|
||||
intType = type;
|
||||
else
|
||||
intType = TypeProvider::uint256();
|
||||
|
||||
auto const& intType = dynamic_cast<IntegerType const&>(*_commonType);
|
||||
smtutil::Expression valueNoMod(
|
||||
_op == Token::Add ? _left + _right :
|
||||
_op == Token::Sub ? _left - _right :
|
||||
_op == Token::Div ? division(_left, _right, intType) :
|
||||
_op == Token::Div ? division(_left, _right, *intType) :
|
||||
_op == Token::Mul ? _left * _right :
|
||||
/*_op == Token::Mod*/ _left % _right
|
||||
);
|
||||
@ -1280,20 +1237,23 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
if (_op == Token::Div || _op == Token::Mod)
|
||||
m_context.addAssertion(_right != 0);
|
||||
|
||||
smtutil::Expression intValueRange = (0 - smt::minValue(intType)) + smt::maxValue(intType) + 1;
|
||||
auto symbMin = smt::minValue(*intType);
|
||||
auto symbMax = smt::maxValue(*intType);
|
||||
|
||||
smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1;
|
||||
auto value = smtutil::Expression::ite(
|
||||
valueNoMod > smt::maxValue(intType),
|
||||
valueNoMod > symbMax,
|
||||
valueNoMod % intValueRange,
|
||||
smtutil::Expression::ite(
|
||||
valueNoMod < smt::minValue(intType),
|
||||
valueNoMod < symbMin,
|
||||
valueNoMod % intValueRange,
|
||||
valueNoMod
|
||||
)
|
||||
);
|
||||
|
||||
if (intType.isSigned())
|
||||
if (intType->isSigned())
|
||||
value = smtutil::Expression::ite(
|
||||
value > smt::maxValue(intType),
|
||||
value > symbMax,
|
||||
value - intValueRange,
|
||||
value
|
||||
);
|
||||
@ -1422,11 +1382,16 @@ smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Exp
|
||||
|
||||
void SMTEncoder::assignment(
|
||||
Expression const& _left,
|
||||
vector<smtutil::Expression> const& _right,
|
||||
smtutil::Expression const& _right,
|
||||
TypePointer const& _type,
|
||||
langutil::SourceLocation const& _location
|
||||
)
|
||||
{
|
||||
solAssert(
|
||||
_left.annotation().type->category() != Type::Category::Tuple,
|
||||
"Tuple assignments should be handled by tupleAssignment."
|
||||
);
|
||||
|
||||
if (!smt::isSupportedType(_type->category()))
|
||||
{
|
||||
// Give it a new index anyway to keep the SSA scheme sound.
|
||||
@ -1440,26 +1405,9 @@ void SMTEncoder::assignment(
|
||||
);
|
||||
}
|
||||
else if (auto varDecl = identifierToVariable(_left))
|
||||
{
|
||||
solAssert(_right.size() == 1, "");
|
||||
assignment(*varDecl, _right.front());
|
||||
}
|
||||
assignment(*varDecl, _right);
|
||||
else if (dynamic_cast<IndexAccess const*>(&_left))
|
||||
{
|
||||
solAssert(_right.size() == 1, "");
|
||||
arrayIndexAssignment(_left, _right.front());
|
||||
}
|
||||
else if (auto tuple = dynamic_cast<TupleExpression const*>(&_left))
|
||||
{
|
||||
auto const& components = tuple->components();
|
||||
if (!_right.empty())
|
||||
{
|
||||
solAssert(_right.size() == components.size(), "");
|
||||
for (unsigned i = 0; i < _right.size(); ++i)
|
||||
if (auto component = components.at(i))
|
||||
assignment(*component, {_right.at(i)}, component->annotation().type, component->location());
|
||||
}
|
||||
}
|
||||
arrayIndexAssignment(_left, _right);
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
8182_error,
|
||||
@ -1468,6 +1416,52 @@ void SMTEncoder::assignment(
|
||||
);
|
||||
}
|
||||
|
||||
void SMTEncoder::tupleAssignment(Expression const& _left, Expression const& _right)
|
||||
{
|
||||
auto lTuple = dynamic_cast<TupleExpression const*>(&_left);
|
||||
solAssert(lTuple, "");
|
||||
|
||||
auto const& lComponents = lTuple->components();
|
||||
|
||||
// If both sides are tuple expressions, we individually and potentially
|
||||
// recursively assign each pair of components.
|
||||
// This is because of potential type conversion.
|
||||
if (auto rTuple = dynamic_cast<TupleExpression const*>(&_right))
|
||||
{
|
||||
auto const& rComponents = rTuple->components();
|
||||
solAssert(lComponents.size() == rComponents.size(), "");
|
||||
for (unsigned i = 0; i < lComponents.size(); ++i)
|
||||
{
|
||||
if (!lComponents.at(i) || !rComponents.at(i))
|
||||
continue;
|
||||
auto const& lExpr = *lComponents.at(i);
|
||||
auto const& rExpr = *rComponents.at(i);
|
||||
if (lExpr.annotation().type->category() == Type::Category::Tuple)
|
||||
tupleAssignment(lExpr, rExpr);
|
||||
else
|
||||
{
|
||||
auto type = lExpr.annotation().type;
|
||||
assignment(lExpr, expr(rExpr, type), type, lExpr.location());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rType = dynamic_cast<TupleType const*>(_right.annotation().type);
|
||||
solAssert(rType, "");
|
||||
|
||||
auto const& rComponents = rType->components();
|
||||
solAssert(lComponents.size() == rComponents.size(), "");
|
||||
|
||||
auto symbRight = expr(_right);
|
||||
solAssert(symbRight.sort->kind == smtutil::Kind::Tuple, "");
|
||||
|
||||
for (unsigned i = 0; i < lComponents.size(); ++i)
|
||||
if (auto component = lComponents.at(i); component && rComponents.at(i))
|
||||
assignment(*component, smtutil::Expression::tuple_get(symbRight, i), component->annotation().type, component->location());
|
||||
}
|
||||
}
|
||||
|
||||
smtutil::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment)
|
||||
{
|
||||
static map<Token, Token> const compoundToArithmetic{
|
||||
@ -1618,6 +1612,42 @@ void SMTEncoder::resetStateVariables()
|
||||
m_context.resetVariables([&](VariableDeclaration const& _variable) { return _variable.isStateVariable(); });
|
||||
}
|
||||
|
||||
void SMTEncoder::resetReferences(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
m_context.resetVariables([&](VariableDeclaration const& _var) {
|
||||
if (_var == _varDecl)
|
||||
return false;
|
||||
|
||||
// If both are state variables no need to clear knowledge.
|
||||
if (_var.isStateVariable() && _varDecl.isStateVariable())
|
||||
return false;
|
||||
|
||||
TypePointer prefix = _var.type();
|
||||
TypePointer originalType = typeWithoutPointer(_varDecl.type());
|
||||
while (
|
||||
prefix->category() == Type::Category::Mapping ||
|
||||
prefix->category() == Type::Category::Array
|
||||
)
|
||||
{
|
||||
if (*originalType == *typeWithoutPointer(prefix))
|
||||
return true;
|
||||
if (prefix->category() == Type::Category::Mapping)
|
||||
{
|
||||
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
|
||||
solAssert(mapPrefix, "");
|
||||
prefix = mapPrefix->valueType();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
|
||||
solAssert(arrayPrefix, "");
|
||||
prefix = arrayPrefix->baseType();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
TypePointer SMTEncoder::typeWithoutPointer(TypePointer const& _type)
|
||||
{
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||
|
@ -157,10 +157,12 @@ protected:
|
||||
/// Will also be used for assignments of tuple components.
|
||||
void assignment(
|
||||
Expression const& _left,
|
||||
std::vector<smtutil::Expression> const& _right,
|
||||
smtutil::Expression const& _right,
|
||||
TypePointer const& _type,
|
||||
langutil::SourceLocation const& _location
|
||||
);
|
||||
/// Handle assignments between tuples.
|
||||
void tupleAssignment(Expression const& _left, Expression const& _right);
|
||||
/// Computes the right hand side of a compound assignment.
|
||||
smtutil::Expression compoundAssignment(Assignment const& _assignment);
|
||||
|
||||
@ -181,6 +183,9 @@ protected:
|
||||
void initializeLocalVariables(FunctionDefinition const& _function);
|
||||
void initializeFunctionCallParameters(CallableDeclaration const& _function, std::vector<smtutil::Expression> const& _callArgs);
|
||||
void resetStateVariables();
|
||||
/// Resets all references/pointers that have the same type or have
|
||||
/// a subexpression of the same type as _varDecl.
|
||||
void resetReferences(VariableDeclaration const& _varDecl);
|
||||
/// @returns the type without storage pointer information if it has it.
|
||||
TypePointer typeWithoutPointer(TypePointer const& _type);
|
||||
|
||||
|
@ -53,9 +53,6 @@ string solidity::util::toHex(uint8_t _data, HexCase _case)
|
||||
|
||||
string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case)
|
||||
{
|
||||
if (_data.empty())
|
||||
return {};
|
||||
|
||||
std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0);
|
||||
|
||||
size_t i = 0;
|
||||
|
@ -359,6 +359,13 @@ void AsmAnalyzer::operator()(Switch const& _switch)
|
||||
{
|
||||
yulAssert(_switch.expression, "");
|
||||
|
||||
if (_switch.cases.size() == 1 && !_switch.cases[0].value)
|
||||
m_errorReporter.warning(
|
||||
9592_error,
|
||||
_switch.location,
|
||||
"\"switch\" statement with only a default case."
|
||||
);
|
||||
|
||||
YulString valueType = expectExpression(*_switch.expression);
|
||||
|
||||
set<u256> cases;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@ -130,7 +131,7 @@ bytes toBytes(Opcode _o)
|
||||
return toBytes(uint8_t(_o));
|
||||
}
|
||||
|
||||
static std::map<string, uint8_t> const builtins = {
|
||||
static map<string, uint8_t> const builtins = {
|
||||
{"i32.load", 0x28},
|
||||
{"i64.load", 0x29},
|
||||
{"i32.load8_s", 0x2c},
|
||||
@ -240,46 +241,56 @@ bytes lebEncodeSigned(int64_t _n)
|
||||
bytes prefixSize(bytes _data)
|
||||
{
|
||||
size_t size = _data.size();
|
||||
return lebEncode(size) + std::move(_data);
|
||||
return lebEncode(size) + move(_data);
|
||||
}
|
||||
|
||||
bytes makeSection(Section _section, bytes _data)
|
||||
{
|
||||
return toBytes(_section) + prefixSize(std::move(_data));
|
||||
return toBytes(_section) + prefixSize(move(_data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bytes BinaryTransform::run(Module const& _module)
|
||||
{
|
||||
BinaryTransform bt;
|
||||
map<Type, vector<string>> const types = typeToFunctionMap(_module.imports, _module.functions);
|
||||
|
||||
for (size_t i = 0; i < _module.globals.size(); ++i)
|
||||
bt.m_globals[_module.globals[i].variableName] = i;
|
||||
map<string, size_t> const globalIDs = enumerateGlobals(_module);
|
||||
map<string, size_t> const functionIDs = enumerateFunctions(_module);
|
||||
map<string, size_t> const functionTypes = enumerateFunctionTypes(types);
|
||||
|
||||
size_t funID = 0;
|
||||
for (FunctionImport const& fun: _module.imports)
|
||||
bt.m_functions[fun.internalName] = funID++;
|
||||
for (FunctionDefinition const& fun: _module.functions)
|
||||
bt.m_functions[fun.name] = funID++;
|
||||
yulAssert(globalIDs.size() == _module.globals.size(), "");
|
||||
yulAssert(functionIDs.size() == _module.imports.size() + _module.functions.size(), "");
|
||||
yulAssert(functionTypes.size() == functionIDs.size(), "");
|
||||
yulAssert(functionTypes.size() >= types.size(), "");
|
||||
|
||||
bytes ret{0, 'a', 's', 'm'};
|
||||
// version
|
||||
ret += bytes{1, 0, 0, 0};
|
||||
ret += bt.typeSection(_module.imports, _module.functions);
|
||||
ret += bt.importSection(_module.imports);
|
||||
ret += bt.functionSection(_module.functions);
|
||||
ret += bt.memorySection();
|
||||
ret += bt.globalSection();
|
||||
ret += bt.exportSection();
|
||||
ret += typeSection(types);
|
||||
ret += importSection(_module.imports, functionTypes);
|
||||
ret += functionSection(_module.functions, functionTypes);
|
||||
ret += memorySection();
|
||||
ret += globalSection(_module.globals);
|
||||
ret += exportSection(functionIDs);
|
||||
|
||||
map<string, pair<size_t, size_t>> subModulePosAndSize;
|
||||
for (auto const& sub: _module.subModules)
|
||||
{
|
||||
// TODO should we prefix and / or shorten the name?
|
||||
bytes data = BinaryTransform::run(sub.second);
|
||||
size_t length = data.size();
|
||||
ret += bt.customSection(sub.first, std::move(data));
|
||||
bt.m_subModulePosAndSize[sub.first] = {ret.size() - length, length};
|
||||
ret += customSection(sub.first, move(data));
|
||||
subModulePosAndSize[sub.first] = {ret.size() - length, length};
|
||||
}
|
||||
|
||||
BinaryTransform bt(
|
||||
move(globalIDs),
|
||||
move(functionIDs),
|
||||
move(functionTypes),
|
||||
move(subModulePosAndSize)
|
||||
);
|
||||
|
||||
ret += bt.codeSection(_module.functions);
|
||||
return ret;
|
||||
}
|
||||
@ -302,7 +313,7 @@ bytes BinaryTransform::operator()(LocalVariable const& _variable)
|
||||
|
||||
bytes BinaryTransform::operator()(GlobalVariable const& _variable)
|
||||
{
|
||||
return toBytes(Opcode::GlobalGet) + lebEncode(m_globals.at(_variable.name));
|
||||
return toBytes(Opcode::GlobalGet) + lebEncode(m_globalIDs.at(_variable.name));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
||||
@ -311,12 +322,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
||||
// they are references to object names that should not end up in the code.
|
||||
if (_call.functionName == "dataoffset")
|
||||
{
|
||||
string name = std::get<StringLiteral>(_call.arguments.at(0)).value;
|
||||
string name = get<StringLiteral>(_call.arguments.at(0)).value;
|
||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first);
|
||||
}
|
||||
else if (_call.functionName == "datasize")
|
||||
{
|
||||
string name = std::get<StringLiteral>(_call.arguments.at(0)).value;
|
||||
string name = get<StringLiteral>(_call.arguments.at(0)).value;
|
||||
return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second);
|
||||
}
|
||||
|
||||
@ -331,20 +342,24 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
||||
else
|
||||
{
|
||||
yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found");
|
||||
bytes ret = std::move(args) + toBytes(builtins.at(_call.functionName));
|
||||
bytes ret = move(args) + toBytes(builtins.at(_call.functionName));
|
||||
if (
|
||||
_call.functionName.find(".load") != string::npos ||
|
||||
_call.functionName.find(".store") != string::npos
|
||||
)
|
||||
// alignment and offset
|
||||
ret += bytes{{3, 0}};
|
||||
// Alignment hint and offset. Interpreters ignore the alignment. JITs/AOTs can take it
|
||||
// into account to generate more efficient code but if the hint is invalid it could
|
||||
// actually be more expensive. It's best to hint at 1-byte alignment if we don't plan
|
||||
// to control the memory layout accordingly.
|
||||
ret += bytes{{0, 0}}; // 2^0 == 1-byte alignment
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bytes BinaryTransform::operator()(FunctionCall const& _call)
|
||||
{
|
||||
return visit(_call.arguments) + toBytes(Opcode::Call) + lebEncode(m_functions.at(_call.functionName));
|
||||
return visit(_call.arguments) + toBytes(Opcode::Call) + lebEncode(m_functionIDs.at(_call.functionName));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::operator()(LocalAssignment const& _assignment)
|
||||
@ -360,7 +375,7 @@ bytes BinaryTransform::operator()(GlobalAssignment const& _assignment)
|
||||
return
|
||||
std::visit(*this, *_assignment.value) +
|
||||
toBytes(Opcode::GlobalSet) +
|
||||
lebEncode(m_globals.at(_assignment.variableName));
|
||||
lebEncode(m_globalIDs.at(_assignment.variableName));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::operator()(If const& _if)
|
||||
@ -430,9 +445,14 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function)
|
||||
|
||||
// This is a kind of run-length-encoding of local types. Has to be adapted once
|
||||
// we have locals of different types.
|
||||
ret += lebEncode(1); // number of locals groups
|
||||
ret += lebEncode(_function.locals.size());
|
||||
ret += toBytes(ValueType::I64);
|
||||
if (_function.locals.size() == 0)
|
||||
ret += lebEncode(0); // number of locals groups
|
||||
else
|
||||
{
|
||||
ret += lebEncode(1); // number of locals groups
|
||||
ret += lebEncode(_function.locals.size());
|
||||
ret += toBytes(ValueType::I64);
|
||||
}
|
||||
|
||||
m_locals.clear();
|
||||
size_t varIdx = 0;
|
||||
@ -448,7 +468,7 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function)
|
||||
|
||||
yulAssert(m_labels.empty(), "Stray labels.");
|
||||
|
||||
return prefixSize(std::move(ret));
|
||||
return prefixSize(move(ret));
|
||||
}
|
||||
|
||||
BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import)
|
||||
@ -487,9 +507,9 @@ vector<uint8_t> BinaryTransform::encodeTypes(vector<string> const& _typeNames)
|
||||
return result;
|
||||
}
|
||||
|
||||
bytes BinaryTransform::typeSection(
|
||||
vector<FunctionImport> const& _imports,
|
||||
vector<FunctionDefinition> const& _functions
|
||||
map<BinaryTransform::Type, vector<string>> BinaryTransform::typeToFunctionMap(
|
||||
vector<wasm::FunctionImport> const& _imports,
|
||||
vector<wasm::FunctionDefinition> const& _functions
|
||||
)
|
||||
{
|
||||
map<Type, vector<string>> types;
|
||||
@ -498,12 +518,50 @@ bytes BinaryTransform::typeSection(
|
||||
for (auto const& fun: _functions)
|
||||
types[typeOf(fun)].emplace_back(fun.name);
|
||||
|
||||
bytes result;
|
||||
size_t index = 0;
|
||||
for (auto const& [type, funNames]: types)
|
||||
return types;
|
||||
}
|
||||
|
||||
map<string, size_t> BinaryTransform::enumerateGlobals(Module const& _module)
|
||||
{
|
||||
map<string, size_t> globals;
|
||||
for (size_t i = 0; i < _module.globals.size(); ++i)
|
||||
globals[_module.globals[i].variableName] = i;
|
||||
|
||||
return globals;
|
||||
}
|
||||
|
||||
map<string, size_t> BinaryTransform::enumerateFunctions(Module const& _module)
|
||||
{
|
||||
map<string, size_t> functions;
|
||||
size_t funID = 0;
|
||||
for (FunctionImport const& fun: _module.imports)
|
||||
functions[fun.internalName] = funID++;
|
||||
for (FunctionDefinition const& fun: _module.functions)
|
||||
functions[fun.name] = funID++;
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
map<string, size_t> BinaryTransform::enumerateFunctionTypes(map<Type, vector<string>> const& _typeToFunctionMap)
|
||||
{
|
||||
map<string, size_t> functionTypes;
|
||||
size_t typeID = 0;
|
||||
for (vector<string> const& funNames: _typeToFunctionMap | boost::adaptors::map_values)
|
||||
{
|
||||
for (string const& name: funNames)
|
||||
m_functionTypes[name] = index;
|
||||
functionTypes[name] = typeID;
|
||||
++typeID;
|
||||
}
|
||||
|
||||
return functionTypes;
|
||||
}
|
||||
|
||||
bytes BinaryTransform::typeSection(map<BinaryTransform::Type, vector<string>> const& _typeToFunctionMap)
|
||||
{
|
||||
bytes result;
|
||||
size_t index = 0;
|
||||
for (Type const& type: _typeToFunctionMap | boost::adaptors::map_keys)
|
||||
{
|
||||
result += toBytes(ValueType::Function);
|
||||
result += lebEncode(type.first.size()) + type.first;
|
||||
result += lebEncode(type.second.size()) + type.second;
|
||||
@ -511,11 +569,12 @@ bytes BinaryTransform::typeSection(
|
||||
index++;
|
||||
}
|
||||
|
||||
return makeSection(Section::TYPE, lebEncode(index) + std::move(result));
|
||||
return makeSection(Section::TYPE, lebEncode(index) + move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::importSection(
|
||||
vector<FunctionImport> const& _imports
|
||||
vector<FunctionImport> const& _imports,
|
||||
map<string, size_t> const& _functionTypes
|
||||
)
|
||||
{
|
||||
bytes result = lebEncode(_imports.size());
|
||||
@ -526,17 +585,20 @@ bytes BinaryTransform::importSection(
|
||||
encodeName(import.module) +
|
||||
encodeName(import.externalName) +
|
||||
toBytes(importKind) +
|
||||
lebEncode(m_functionTypes[import.internalName]);
|
||||
lebEncode(_functionTypes.at(import.internalName));
|
||||
}
|
||||
return makeSection(Section::IMPORT, std::move(result));
|
||||
return makeSection(Section::IMPORT, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::functionSection(vector<FunctionDefinition> const& _functions)
|
||||
bytes BinaryTransform::functionSection(
|
||||
vector<FunctionDefinition> const& _functions,
|
||||
map<string, size_t> const& _functionTypes
|
||||
)
|
||||
{
|
||||
bytes result = lebEncode(_functions.size());
|
||||
for (auto const& fun: _functions)
|
||||
result += lebEncode(m_functionTypes.at(fun.name));
|
||||
return makeSection(Section::FUNCTION, std::move(result));
|
||||
result += lebEncode(_functionTypes.at(fun.name));
|
||||
return makeSection(Section::FUNCTION, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::memorySection()
|
||||
@ -544,13 +606,13 @@ bytes BinaryTransform::memorySection()
|
||||
bytes result = lebEncode(1);
|
||||
result.push_back(static_cast<uint8_t>(LimitsKind::Min));
|
||||
result.push_back(1); // initial length
|
||||
return makeSection(Section::MEMORY, std::move(result));
|
||||
return makeSection(Section::MEMORY, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::globalSection()
|
||||
bytes BinaryTransform::globalSection(vector<wasm::GlobalVariableDeclaration> const& _globals)
|
||||
{
|
||||
bytes result = lebEncode(m_globals.size());
|
||||
for (size_t i = 0; i < m_globals.size(); ++i)
|
||||
bytes result = lebEncode(_globals.size());
|
||||
for (size_t i = 0; i < _globals.size(); ++i)
|
||||
result +=
|
||||
toBytes(ValueType::I64) +
|
||||
lebEncode(static_cast<uint8_t>(Mutability::Var)) +
|
||||
@ -558,21 +620,21 @@ bytes BinaryTransform::globalSection()
|
||||
lebEncodeSigned(0) +
|
||||
toBytes(Opcode::End);
|
||||
|
||||
return makeSection(Section::GLOBAL, std::move(result));
|
||||
return makeSection(Section::GLOBAL, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::exportSection()
|
||||
bytes BinaryTransform::exportSection(map<string, size_t> const& _functionIDs)
|
||||
{
|
||||
bytes result = lebEncode(2);
|
||||
result += encodeName("memory") + toBytes(Export::Memory) + lebEncode(0);
|
||||
result += encodeName("main") + toBytes(Export::Function) + lebEncode(m_functions.at("main"));
|
||||
return makeSection(Section::EXPORT, std::move(result));
|
||||
result += encodeName("main") + toBytes(Export::Function) + lebEncode(_functionIDs.at("main"));
|
||||
return makeSection(Section::EXPORT, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::customSection(string const& _name, bytes _data)
|
||||
{
|
||||
bytes result = encodeName(_name) + std::move(_data);
|
||||
return makeSection(Section::CUSTOM, std::move(result));
|
||||
bytes result = encodeName(_name) + move(_data);
|
||||
return makeSection(Section::CUSTOM, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::codeSection(vector<wasm::FunctionDefinition> const& _functions)
|
||||
@ -580,7 +642,7 @@ bytes BinaryTransform::codeSection(vector<wasm::FunctionDefinition> const& _func
|
||||
bytes result = lebEncode(_functions.size());
|
||||
for (FunctionDefinition const& fun: _functions)
|
||||
result += (*this)(fun);
|
||||
return makeSection(Section::CODE, std::move(result));
|
||||
return makeSection(Section::CODE, move(result));
|
||||
}
|
||||
|
||||
bytes BinaryTransform::visit(vector<Expression> const& _expressions)
|
||||
@ -611,7 +673,7 @@ bytes BinaryTransform::encodeLabelIdx(string const& _label) const
|
||||
yulAssert(false, "Label not found.");
|
||||
}
|
||||
|
||||
bytes BinaryTransform::encodeName(std::string const& _name)
|
||||
bytes BinaryTransform::encodeName(string const& _name)
|
||||
{
|
||||
// UTF-8 is allowed here by the Wasm spec, but since all names here should stem from
|
||||
// Solidity or Yul identifiers or similar, non-ascii characters ending up here
|
||||
|
@ -55,23 +55,49 @@ public:
|
||||
bytes operator()(wasm::FunctionDefinition const& _function);
|
||||
|
||||
private:
|
||||
BinaryTransform(
|
||||
std::map<std::string, size_t> _globalIDs,
|
||||
std::map<std::string, size_t> _functionIDs,
|
||||
std::map<std::string, size_t> _functionTypes,
|
||||
std::map<std::string, std::pair<size_t, size_t>> _subModulePosAndSize
|
||||
):
|
||||
m_globalIDs(std::move(_globalIDs)),
|
||||
m_functionIDs(std::move(_functionIDs)),
|
||||
m_functionTypes(std::move(_functionTypes)),
|
||||
m_subModulePosAndSize(std::move(_subModulePosAndSize))
|
||||
{}
|
||||
|
||||
using Type = std::pair<std::vector<std::uint8_t>, std::vector<std::uint8_t>>;
|
||||
static Type typeOf(wasm::FunctionImport const& _import);
|
||||
static Type typeOf(wasm::FunctionDefinition const& _funDef);
|
||||
|
||||
static uint8_t encodeType(std::string const& _typeName);
|
||||
static std::vector<uint8_t> encodeTypes(std::vector<std::string> const& _typeNames);
|
||||
bytes typeSection(
|
||||
|
||||
static std::map<Type, std::vector<std::string>> typeToFunctionMap(
|
||||
std::vector<wasm::FunctionImport> const& _imports,
|
||||
std::vector<wasm::FunctionDefinition> const& _functions
|
||||
);
|
||||
|
||||
bytes importSection(std::vector<wasm::FunctionImport> const& _imports);
|
||||
bytes functionSection(std::vector<wasm::FunctionDefinition> const& _functions);
|
||||
bytes memorySection();
|
||||
bytes globalSection();
|
||||
bytes exportSection();
|
||||
bytes customSection(std::string const& _name, bytes _data);
|
||||
static std::map<std::string, size_t> enumerateGlobals(Module const& _module);
|
||||
static std::map<std::string, size_t> enumerateFunctions(Module const& _module);
|
||||
static std::map<std::string, size_t> enumerateFunctionTypes(
|
||||
std::map<Type, std::vector<std::string>> const& _typeToFunctionMap
|
||||
);
|
||||
|
||||
static bytes typeSection(std::map<Type, std::vector<std::string>> const& _typeToFunctionMap);
|
||||
static bytes importSection(
|
||||
std::vector<wasm::FunctionImport> const& _imports,
|
||||
std::map<std::string, size_t> const& _functionTypes
|
||||
);
|
||||
static bytes functionSection(
|
||||
std::vector<wasm::FunctionDefinition> const& _functions,
|
||||
std::map<std::string, size_t> const& _functionTypes
|
||||
);
|
||||
static bytes memorySection();
|
||||
static bytes globalSection(std::vector<wasm::GlobalVariableDeclaration> const& _globals);
|
||||
static bytes exportSection(std::map<std::string, size_t> const& _functionIDs);
|
||||
static bytes customSection(std::string const& _name, bytes _data);
|
||||
bytes codeSection(std::vector<wasm::FunctionDefinition> const& _functions);
|
||||
|
||||
bytes visit(std::vector<wasm::Expression> const& _expressions);
|
||||
@ -81,12 +107,13 @@ private:
|
||||
|
||||
static bytes encodeName(std::string const& _name);
|
||||
|
||||
std::map<std::string, size_t> const m_globalIDs;
|
||||
std::map<std::string, size_t> const m_functionIDs;
|
||||
std::map<std::string, size_t> const m_functionTypes;
|
||||
std::map<std::string, std::pair<size_t, size_t>> const m_subModulePosAndSize;
|
||||
|
||||
std::map<std::string, size_t> m_locals;
|
||||
std::map<std::string, size_t> m_globals;
|
||||
std::map<std::string, size_t> m_functions;
|
||||
std::map<std::string, size_t> m_functionTypes;
|
||||
std::vector<std::string> m_labels;
|
||||
std::map<std::string, std::pair<size_t, size_t>> m_subModulePosAndSize;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -33,16 +33,16 @@ using namespace solidity::yul;
|
||||
VarNameCleaner::VarNameCleaner(
|
||||
Block const& _ast,
|
||||
Dialect const& _dialect,
|
||||
set<YulString> _blacklist
|
||||
set<YulString> _namesToKeep
|
||||
):
|
||||
m_dialect{_dialect},
|
||||
m_blacklist{std::move(_blacklist)},
|
||||
m_namesToKeep{std::move(_namesToKeep)},
|
||||
m_translatedNames{}
|
||||
{
|
||||
for (auto const& statement: _ast.statements)
|
||||
if (holds_alternative<FunctionDefinition>(statement))
|
||||
m_blacklist.insert(std::get<FunctionDefinition>(statement).name);
|
||||
m_usedNames = m_blacklist;
|
||||
m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
|
||||
m_usedNames = m_namesToKeep;
|
||||
}
|
||||
|
||||
void VarNameCleaner::operator()(FunctionDefinition& _funDef)
|
||||
@ -51,7 +51,7 @@ void VarNameCleaner::operator()(FunctionDefinition& _funDef)
|
||||
m_insideFunction = true;
|
||||
|
||||
set<YulString> globalUsedNames = std::move(m_usedNames);
|
||||
m_usedNames = m_blacklist;
|
||||
m_usedNames = m_namesToKeep;
|
||||
map<YulString, YulString> globalTranslatedNames;
|
||||
swap(globalTranslatedNames, m_translatedNames);
|
||||
|
||||
|
@ -63,7 +63,7 @@ private:
|
||||
VarNameCleaner(
|
||||
Block const& _ast,
|
||||
Dialect const& _dialect,
|
||||
std::set<YulString> _blacklist = {}
|
||||
std::set<YulString> _namesToKeep = {}
|
||||
);
|
||||
|
||||
/// Tries to rename a list of variables.
|
||||
@ -77,11 +77,13 @@ private:
|
||||
YulString findCleanName(YulString const& name) const;
|
||||
|
||||
/// Tests whether a given name was already used within this pass
|
||||
/// or is on the blacklist.
|
||||
/// or was set to be kept.
|
||||
bool isUsedName(YulString const& _name) const;
|
||||
|
||||
Dialect const& m_dialect;
|
||||
std::set<YulString> m_blacklist;
|
||||
|
||||
/// These names will not be modified.
|
||||
std::set<YulString> m_namesToKeep;
|
||||
|
||||
/// Set of names that are in use.
|
||||
std::set<YulString> m_usedNames;
|
||||
|
@ -54,6 +54,10 @@ cmake \
|
||||
-DTESTS=0 \
|
||||
..
|
||||
make -j 4 soljson
|
||||
# Patch soljson.js for backwards compatibility.
|
||||
# TODO: remove this with 0.7.
|
||||
# "viiiii" encodes the signature of the callback function.
|
||||
sed -i -e 's/addFunction(func,sig){/addFunction(func,sig){sig=sig||"viiiii";/' libsolc/soljson.js
|
||||
|
||||
cd ..
|
||||
mkdir -p upload
|
||||
|
@ -740,7 +740,7 @@ remap paths using the context:prefix=path syntax.
|
||||
Example:
|
||||
solc --)" + g_argBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol
|
||||
|
||||
Allowed options)").c_str(),
|
||||
General Information)").c_str(),
|
||||
po::options_description::m_default_line_length,
|
||||
po::options_description::m_default_line_length - 23
|
||||
);
|
||||
@ -748,47 +748,67 @@ Allowed options)").c_str(),
|
||||
(g_argHelp.c_str(), "Show help message and exit.")
|
||||
(g_argVersion.c_str(), "Show version and exit.")
|
||||
(g_strLicense.c_str(), "Show licensing information and exit.")
|
||||
;
|
||||
|
||||
po::options_description inputOptions("Input Options");
|
||||
inputOptions.add_options()
|
||||
(
|
||||
g_argBasePath.c_str(),
|
||||
po::value<string>()->value_name("path"),
|
||||
"Use the given path as the root of the source tree instead of the root of the filesystem."
|
||||
)
|
||||
(
|
||||
g_argAllowPaths.c_str(),
|
||||
po::value<string>()->value_name("path(s)"),
|
||||
"Allow a given path for imports. A list of paths can be supplied by separating them with a comma."
|
||||
)
|
||||
(
|
||||
g_argIgnoreMissingFiles.c_str(),
|
||||
"Ignore missing files."
|
||||
)
|
||||
(
|
||||
g_argErrorRecovery.c_str(),
|
||||
"Enables additional parser error recovery."
|
||||
)
|
||||
;
|
||||
desc.add(inputOptions);
|
||||
|
||||
po::options_description outputOptions("Output Options");
|
||||
outputOptions.add_options()
|
||||
(
|
||||
(g_argOutputDir + ",o").c_str(),
|
||||
po::value<string>()->value_name("path"),
|
||||
"If given, creates one file per component and contract/file at the specified directory."
|
||||
)
|
||||
(
|
||||
g_strOverwrite.c_str(),
|
||||
"Overwrite existing files (used together with -o)."
|
||||
)
|
||||
(
|
||||
g_strEVMVersion.c_str(),
|
||||
po::value<string>()->value_name("version"),
|
||||
"Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, "
|
||||
"byzantium, constantinople, petersburg, istanbul (default) or berlin."
|
||||
)
|
||||
(g_argPrettyJson.c_str(), "Output JSON in pretty format. Currently it only works with the combined JSON output.")
|
||||
(
|
||||
g_argLibraries.c_str(),
|
||||
po::value<vector<string>>()->value_name("libs"),
|
||||
"Direct string or file containing library addresses. Syntax: "
|
||||
"<libraryName>:<address> [, or whitespace] ...\n"
|
||||
"Address is interpreted as a hex string optionally prefixed by 0x."
|
||||
)
|
||||
(
|
||||
g_strRevertStrings.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_revertStringsArgs, ",")),
|
||||
"Strip revert (and require) reason strings or add additional debugging information."
|
||||
)
|
||||
(
|
||||
(g_argOutputDir + ",o").c_str(),
|
||||
po::value<string>()->value_name("path"),
|
||||
"If given, creates one file per component and contract/file at the specified directory."
|
||||
)
|
||||
(g_strOverwrite.c_str(), "Overwrite existing files (used together with -o).")
|
||||
(
|
||||
g_argCombinedJson.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_combinedJsonArgs, ",")),
|
||||
"Output a single json document containing the specified information."
|
||||
)
|
||||
(g_argGas.c_str(), "Print an estimate of the maximal gas usage for each function.")
|
||||
;
|
||||
desc.add(outputOptions);
|
||||
|
||||
po::options_description alternativeInputModes("Alternative Input Modes");
|
||||
alternativeInputModes.add_options()
|
||||
(
|
||||
g_argStandardJSON.c_str(),
|
||||
"Switch to Standard JSON input / output mode, ignoring all options. "
|
||||
"It reads from standard input, if no input file was given, otherwise it reads from the provided input file. The result will be written to standard output."
|
||||
)
|
||||
(
|
||||
g_argImportAst.c_str(),
|
||||
("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. "
|
||||
"Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by "
|
||||
"--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str()
|
||||
g_argLink.c_str(),
|
||||
("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " "
|
||||
"and modify binaries in place.").c_str()
|
||||
)
|
||||
(
|
||||
g_argAssemble.c_str(),
|
||||
@ -809,58 +829,62 @@ Allowed options)").c_str(),
|
||||
"and assumes input is strict assembly.").c_str()
|
||||
)
|
||||
(
|
||||
g_strYulDialect.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_yulDialectArgs, ",")),
|
||||
"Input dialect to use in assembly or yul mode."
|
||||
g_argImportAst.c_str(),
|
||||
("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. "
|
||||
"Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by "
|
||||
"--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str()
|
||||
)
|
||||
;
|
||||
desc.add(alternativeInputModes);
|
||||
|
||||
po::options_description assemblyModeOptions("Assembly Mode Options");
|
||||
assemblyModeOptions.add_options()
|
||||
(
|
||||
g_argMachine.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_machineArgs, ",")),
|
||||
"Target machine in assembly or Yul mode."
|
||||
)
|
||||
(
|
||||
g_argLink.c_str(),
|
||||
("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " "
|
||||
"and modify binaries in place.").c_str()
|
||||
g_strYulDialect.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_yulDialectArgs, ",")),
|
||||
"Input dialect to use in assembly or yul mode."
|
||||
)
|
||||
;
|
||||
desc.add(assemblyModeOptions);
|
||||
|
||||
po::options_description linkerModeOptions("Linker Mode Options");
|
||||
linkerModeOptions.add_options()
|
||||
(
|
||||
g_argLibraries.c_str(),
|
||||
po::value<vector<string>>()->value_name("libs"),
|
||||
"Direct string or file containing library addresses. Syntax: "
|
||||
"<libraryName>:<address> [, or whitespace] ...\n"
|
||||
"Address is interpreted as a hex string optionally prefixed by 0x."
|
||||
)
|
||||
;
|
||||
desc.add(linkerModeOptions);
|
||||
|
||||
po::options_description outputFormatting("Output Formatting");
|
||||
outputFormatting.add_options()
|
||||
(
|
||||
g_argPrettyJson.c_str(),
|
||||
"Output JSON in pretty format. Currently it only works with the combined JSON output."
|
||||
)
|
||||
(
|
||||
g_argMetadataHash.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_metadataHashArgs, ",")),
|
||||
"Choose hash method for the bytecode metadata or disable it."
|
||||
)
|
||||
(g_argMetadataLiteral.c_str(), "Store referenced sources as literal data in the metadata output.")
|
||||
(
|
||||
g_argAllowPaths.c_str(),
|
||||
po::value<string>()->value_name("path(s)"),
|
||||
"Allow a given path for imports. A list of paths can be supplied by separating them with a comma."
|
||||
g_argColor.c_str(),
|
||||
"Force colored output."
|
||||
)
|
||||
(
|
||||
g_argBasePath.c_str(),
|
||||
po::value<string>()->value_name("path"),
|
||||
"Use the given path as the root of the source tree instead of the root of the filesystem."
|
||||
g_argNoColor.c_str(),
|
||||
"Explicitly disable colored output, disabling terminal auto-detection."
|
||||
)
|
||||
(g_argColor.c_str(), "Force colored output.")
|
||||
(g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection.")
|
||||
(g_argOldReporter.c_str(), "Enables old diagnostics reporter.")
|
||||
(g_argErrorRecovery.c_str(), "Enables additional parser error recovery.")
|
||||
(g_argIgnoreMissingFiles.c_str(), "Ignore missing files.");
|
||||
po::options_description optimizerOptions("Optimizer options");
|
||||
optimizerOptions.add_options()
|
||||
(g_argOptimize.c_str(), "Enable bytecode optimizer.")
|
||||
(
|
||||
g_argOptimizeRuns.c_str(),
|
||||
po::value<unsigned>()->value_name("n")->default_value(200),
|
||||
"Set for how many contract runs to optimize. "
|
||||
"Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage."
|
||||
g_argOldReporter.c_str(),
|
||||
"Enables old diagnostics reporter (legacy option, will be removed)."
|
||||
)
|
||||
(g_strOptimizeYul.c_str(), ("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str())
|
||||
(g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.")
|
||||
(
|
||||
g_strYulOptimizations.c_str(),
|
||||
po::value<string>()->value_name("steps"),
|
||||
"Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one."
|
||||
);
|
||||
desc.add(optimizerOptions);
|
||||
;
|
||||
desc.add(outputFormatting);
|
||||
|
||||
po::options_description outputComponents("Output Components");
|
||||
outputComponents.add_options()
|
||||
(g_argAstJson.c_str(), "AST of all source files in JSON format.")
|
||||
@ -878,9 +902,66 @@ Allowed options)").c_str(),
|
||||
(g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.")
|
||||
(g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.")
|
||||
(g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.")
|
||||
(g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables.");
|
||||
(g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables.")
|
||||
;
|
||||
desc.add(outputComponents);
|
||||
|
||||
po::options_description extraOutput("Extra Output");
|
||||
extraOutput.add_options()
|
||||
(
|
||||
g_argGas.c_str(),
|
||||
"Print an estimate of the maximal gas usage for each function."
|
||||
)
|
||||
(
|
||||
g_argCombinedJson.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_combinedJsonArgs, ",")),
|
||||
"Output a single json document containing the specified information."
|
||||
)
|
||||
;
|
||||
desc.add(extraOutput);
|
||||
|
||||
po::options_description metadataOptions("Metadata Options");
|
||||
metadataOptions.add_options()
|
||||
(
|
||||
g_argMetadataHash.c_str(),
|
||||
po::value<string>()->value_name(boost::join(g_metadataHashArgs, ",")),
|
||||
"Choose hash method for the bytecode metadata or disable it."
|
||||
)
|
||||
(
|
||||
g_argMetadataLiteral.c_str(),
|
||||
"Store referenced sources as literal data in the metadata output."
|
||||
)
|
||||
;
|
||||
desc.add(metadataOptions);
|
||||
|
||||
po::options_description optimizerOptions("Optimizer Options");
|
||||
optimizerOptions.add_options()
|
||||
(
|
||||
g_argOptimize.c_str(),
|
||||
"Enable bytecode optimizer."
|
||||
)
|
||||
(
|
||||
g_argOptimizeRuns.c_str(),
|
||||
po::value<unsigned>()->value_name("n")->default_value(200),
|
||||
"Set for how many contract runs to optimize. "
|
||||
"Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage."
|
||||
)
|
||||
(
|
||||
g_strOptimizeYul.c_str(),
|
||||
("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str()
|
||||
)
|
||||
(
|
||||
g_strNoOptimizeYul.c_str(),
|
||||
"Disable Yul optimizer in Solidity."
|
||||
)
|
||||
(
|
||||
g_strYulOptimizations.c_str(),
|
||||
po::value<string>()->value_name("steps"),
|
||||
"Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one."
|
||||
)
|
||||
;
|
||||
desc.add(optimizerOptions);
|
||||
|
||||
po::options_description allOptions = desc;
|
||||
allOptions.add_options()(g_argInputFile.c_str(), po::value<vector<string>>(), "input file");
|
||||
|
||||
|
@ -45,7 +45,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acd01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b4101007e02402000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b0b
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acb01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b3f0002402000a7200110043700002000a74208a76aada7200210043700002000a74210a76aada7200310043700002000a74218a76aada7200410043700000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
|
@ -154,7 +154,7 @@ object "object" {
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa9090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b4101007e02402000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b0b2701007e024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b
|
||||
0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa5090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290000100c21084200a74208a76aada7290000100c21094200a74210a76aada7290000100c210a4200a74218a76aada7290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3f0002402000a72001100c3700002000a74208a76aada72002100c3700002000a74210a76aada72003100c3700002000a74218a76aada72004100c3700000b0b2500024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
|
@ -0,0 +1 @@
|
||||
--yul --yul-dialect ewasm --machine ewasm
|
@ -0,0 +1 @@
|
||||
Warning: Yul is still experimental. Please use the output with care.
|
@ -0,0 +1,8 @@
|
||||
object "object" {
|
||||
code {
|
||||
function main()
|
||||
{
|
||||
i64.store8(0x01:i32, 42:i64)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
|
||||
======= wasm_to_wasm_memory_instructions_alignment/input.yul (Ewasm) =======
|
||||
|
||||
Pretty printed source:
|
||||
object "object" {
|
||||
code {
|
||||
function main()
|
||||
{ i64.store8(0x01:i32, 42) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0f010d0002404201a7422a3c00000b0b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
(memory $memory (export "memory") 1)
|
||||
(export "main" (func $main))
|
||||
|
||||
(func $main
|
||||
(block $label_
|
||||
(i64.store8 (i32.wrap_i64 (i64.const 1)) (i64.const 42))
|
||||
)
|
||||
)
|
||||
|
||||
)
|
@ -31,14 +31,14 @@
|
||||
{
|
||||
"id": 4,
|
||||
"nodeType": "Block",
|
||||
"src": "42:48:1",
|
||||
"src": "42:58:1",
|
||||
"statements":
|
||||
[
|
||||
{
|
||||
"AST":
|
||||
{
|
||||
"nodeType": "YulBlock",
|
||||
"src": "61:23:1",
|
||||
"src": "61:33:1",
|
||||
"statements":
|
||||
[
|
||||
{
|
||||
@ -48,11 +48,29 @@
|
||||
"body":
|
||||
{
|
||||
"nodeType": "YulBlock",
|
||||
"src": "80:2:1",
|
||||
"src": "79:2:1",
|
||||
"statements": []
|
||||
},
|
||||
"nodeType": "YulCase",
|
||||
"src": "72:10:1",
|
||||
"src": "72:9:1",
|
||||
"value":
|
||||
{
|
||||
"kind": "number",
|
||||
"nodeType": "YulLiteral",
|
||||
"src": "77:1:1",
|
||||
"type": "",
|
||||
"value": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"body":
|
||||
{
|
||||
"nodeType": "YulBlock",
|
||||
"src": "90:2:1",
|
||||
"statements": []
|
||||
},
|
||||
"nodeType": "YulCase",
|
||||
"src": "82:10:1",
|
||||
"value": "default"
|
||||
}
|
||||
],
|
||||
@ -65,7 +83,7 @@
|
||||
"value": "0"
|
||||
},
|
||||
"nodeType": "YulSwitch",
|
||||
"src": "63:19:1"
|
||||
"src": "63:29:1"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -73,7 +91,7 @@
|
||||
"externalReferences": [],
|
||||
"id": 3,
|
||||
"nodeType": "InlineAssembly",
|
||||
"src": "52:32:1"
|
||||
"src": "52:42:1"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -99,15 +117,15 @@
|
||||
"src": "42:0:1"
|
||||
},
|
||||
"scope": 6,
|
||||
"src": "17:73:1",
|
||||
"src": "17:83:1",
|
||||
"stateMutability": "view",
|
||||
"virtual": false,
|
||||
"visibility": "public"
|
||||
}
|
||||
],
|
||||
"scope": 7,
|
||||
"src": "0:92:1"
|
||||
"src": "0:102:1"
|
||||
}
|
||||
],
|
||||
"src": "0:93:1"
|
||||
"src": "0:103:1"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
contract C {
|
||||
function g() view public {
|
||||
assembly { switch 0 default {} }
|
||||
assembly { switch 0 case 0 {} default {} }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,30 +91,30 @@
|
||||
[
|
||||
null
|
||||
],
|
||||
"operations": "{\n switch 0\n default { }\n}"
|
||||
"operations": "{\n switch 0\n case 0 { }\n default { }\n}"
|
||||
},
|
||||
"children": [],
|
||||
"id": 3,
|
||||
"name": "InlineAssembly",
|
||||
"src": "52:32:1"
|
||||
"src": "52:42:1"
|
||||
}
|
||||
],
|
||||
"id": 4,
|
||||
"name": "Block",
|
||||
"src": "42:48:1"
|
||||
"src": "42:58:1"
|
||||
}
|
||||
],
|
||||
"id": 5,
|
||||
"name": "FunctionDefinition",
|
||||
"src": "17:73:1"
|
||||
"src": "17:83:1"
|
||||
}
|
||||
],
|
||||
"id": 6,
|
||||
"name": "ContractDefinition",
|
||||
"src": "0:92:1"
|
||||
"src": "0:102:1"
|
||||
}
|
||||
],
|
||||
"id": 7,
|
||||
"name": "SourceUnit",
|
||||
"src": "0:93:1"
|
||||
"src": "0:103:1"
|
||||
}
|
||||
|
@ -314,9 +314,17 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
|
||||
{
|
||||
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal or identifier expected.");
|
||||
CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' but got reserved keyword 'default'");
|
||||
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to evaluate to one value, but got 0 values instead.");
|
||||
CHECK_PARSE_ERROR("{ switch {} case 1 {} default {} }", ParserError, "Literal or identifier expected.");
|
||||
CHECK_PARSE_ERROR(
|
||||
"{ switch mload case 1 {} default {} }",
|
||||
ParserError,
|
||||
"Expected '(' but got reserved keyword 'case'"
|
||||
);
|
||||
CHECK_PARSE_ERROR(
|
||||
"{ switch mstore(1, 1) case 1 {} default {} }",
|
||||
TypeError,
|
||||
"Expected expression to evaluate to one value, but got 0 values instead."
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(switch_default_before_case)
|
||||
|
20
test/libsolidity/semanticTests/array/index_access.sol
Normal file
20
test/libsolidity/semanticTests/array/index_access.sol
Normal file
@ -0,0 +1,20 @@
|
||||
contract C {
|
||||
function to_little_endian_64(uint64 value) public pure returns (bytes memory ret) {
|
||||
ret = new bytes(8);
|
||||
bytes8 bytesValue = bytes8(value);
|
||||
// Byteswapping during copying to bytes.
|
||||
ret[0] = bytesValue[7];
|
||||
ret[1] = bytesValue[6];
|
||||
ret[2] = bytesValue[5];
|
||||
ret[3] = bytesValue[4];
|
||||
ret[4] = bytesValue[3];
|
||||
ret[5] = bytesValue[2];
|
||||
ret[6] = bytesValue[1];
|
||||
ret[7] = bytesValue[0];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// to_little_endian_64(uint64): 0 -> 0x20, 8, 0x00
|
||||
// to_little_endian_64(uint64): 0x0102030405060708 -> 0x20, 8, 0x0807060504030201000000000000000000000000000000000000000000000000
|
@ -0,0 +1,29 @@
|
||||
contract C {
|
||||
struct Y {
|
||||
uint a;
|
||||
uint b;
|
||||
}
|
||||
mapping(uint256 => Y)[] public m;
|
||||
mapping(uint256 => Y)[3] public n;
|
||||
constructor() public {
|
||||
m.push();
|
||||
m.push();
|
||||
m[1][0].a = 1;
|
||||
m[1][0].b = 2;
|
||||
m[1][1].a = 3;
|
||||
m[1][1].b = 4;
|
||||
n[1][0].a = 7;
|
||||
n[1][0].b = 8;
|
||||
n[1][1].a = 9;
|
||||
n[1][1].b = 10;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// m(uint256,uint256): 0, 0 -> 0x00, 0x00
|
||||
// m(uint256,uint256): 1, 0 -> 1, 2
|
||||
// m(uint256,uint256): 1, 1 -> 3, 4
|
||||
// m(uint256,uint256): 1, 2 -> 0x00, 0x00
|
||||
// n(uint256,uint256): 0, 0 -> 0x00, 0x00
|
||||
// n(uint256,uint256): 1, 0 -> 7, 8
|
||||
// n(uint256,uint256): 1, 1 -> 9, 0x0a
|
||||
// n(uint256,uint256): 1, 2 -> 0x00, 0x00
|
@ -0,0 +1,27 @@
|
||||
contract C {
|
||||
struct Y {
|
||||
uint a;
|
||||
uint b;
|
||||
}
|
||||
mapping(uint256 => Y[]) public m;
|
||||
mapping(uint256 => Y[3]) public n;
|
||||
constructor() public {
|
||||
m[1].push().a = 1;
|
||||
m[1][0].b = 2;
|
||||
m[1].push().a = 3;
|
||||
m[1][1].b = 4;
|
||||
n[1][0].a = 7;
|
||||
n[1][0].b = 8;
|
||||
n[1][1].a = 9;
|
||||
n[1][1].b = 10;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// m(uint256,uint256): 0, 0 -> FAILURE
|
||||
// m(uint256,uint256): 1, 0 -> 1, 2
|
||||
// m(uint256,uint256): 1, 1 -> 3, 4
|
||||
// m(uint256,uint256): 1, 2 -> FAILURE
|
||||
// n(uint256,uint256): 0, 0 -> 0x00, 0x00
|
||||
// n(uint256,uint256): 1, 0 -> 7, 8
|
||||
// n(uint256,uint256): 1, 1 -> 9, 0x0a
|
||||
// n(uint256,uint256): 1, 2 -> 0x00, 0x00
|
18
test/libsolidity/semanticTests/getters/mapping_of_string.sol
Normal file
18
test/libsolidity/semanticTests/getters/mapping_of_string.sol
Normal file
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
mapping(string => uint8[3]) public x;
|
||||
constructor() public {
|
||||
x["abc"][0] = 1;
|
||||
x["abc"][2] = 3;
|
||||
x["abc"][1] = 2;
|
||||
x["def"][1] = 9;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x(string,uint256): 0x40, 0, 3, "abc" -> 1
|
||||
// x(string,uint256): 0x40, 1, 3, "abc" -> 2
|
||||
// x(string,uint256): 0x40, 2, 3, "abc" -> 3
|
||||
// x(string,uint256): 0x40, 0, 3, "def" -> 0x00
|
||||
// x(string,uint256): 0x40, 1, 3, "def" -> 9
|
||||
// x(string,uint256): 0x40, 2, 3, "def" -> 0x00
|
18
test/libsolidity/semanticTests/getters/struct_with_bytes.sol
Normal file
18
test/libsolidity/semanticTests/getters/struct_with_bytes.sol
Normal file
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint a;
|
||||
bytes b;
|
||||
mapping(uint => uint) c;
|
||||
uint[] d;
|
||||
}
|
||||
uint shifter;
|
||||
S public s;
|
||||
constructor() public {
|
||||
s.a = 7;
|
||||
s.b = "abc";
|
||||
s.c[0] = 9;
|
||||
s.d.push(10);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// s() -> 7, 0x40, 3, 0x6162630000000000000000000000000000000000000000000000000000000000
|
@ -0,0 +1,23 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
uint[][] a;
|
||||
uint[][][] c;
|
||||
uint[] d;
|
||||
function f() public {
|
||||
a.push();
|
||||
uint[] storage b = a[0];
|
||||
c[0][0][0] = 12;
|
||||
d[5] = 7;
|
||||
b.push(8);
|
||||
assert(a[0].length == 0);
|
||||
// Safe but knowledge about `c` is erased because `b` could be pointing to `c[x][y]`.
|
||||
assert(c[0][0][0] == 12);
|
||||
// Safe but knowledge about `d` is erased because `b` could be pointing to `d`.
|
||||
assert(d[5] == 7);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (193-217): Assertion violation happens here
|
||||
// Warning: (309-333): Assertion violation happens here
|
||||
// Warning: (419-436): Assertion violation happens here
|
@ -0,0 +1,12 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f() internal pure {
|
||||
ufixed a = uint64(1) + ufixed(2);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (80-88): Unused local variable.
|
||||
// Warning: (91-100): Type conversion is not yet fully supported and might yield false positives.
|
||||
// Warning: (103-112): Type conversion is not yet fully supported and might yield false positives.
|
||||
// Warning: (91-112): Underflow (resulting value less than 0) happens here
|
||||
// Warning: (91-112): Overflow (resulting value larger than 2**256 - 1) happens here
|
@ -0,0 +1,8 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
fixed[] b;
|
||||
function f() internal { b[0] += 1; }
|
||||
}
|
||||
// ----
|
||||
// Warning: (84-93): Underflow (resulting value less than 0) happens here
|
||||
// Warning: (84-93): Overflow (resulting value larger than 2**256 - 1) happens here
|
6
test/libsolidity/smtCheckerTests/types/tuple_tuple.sol
Normal file
6
test/libsolidity/smtCheckerTests/types/tuple_tuple.sol
Normal file
@ -0,0 +1,6 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
function f3() public pure {
|
||||
((, ), ) = ((7, 8), 9);
|
||||
}
|
||||
}
|
@ -1,15 +1,7 @@
|
||||
contract C {
|
||||
struct S { bool f; }
|
||||
S s;
|
||||
function f(uint256 a) internal pure {
|
||||
S storage c;
|
||||
assembly {
|
||||
switch a
|
||||
default { c_slot := s_slot }
|
||||
}
|
||||
c;
|
||||
}
|
||||
function g(bool flag) internal pure {
|
||||
function f(bool flag) internal pure {
|
||||
S storage c;
|
||||
assembly {
|
||||
switch flag
|
||||
@ -18,7 +10,7 @@ contract C {
|
||||
}
|
||||
c;
|
||||
}
|
||||
function h(uint256 a) internal pure {
|
||||
function g(uint256 a) internal pure {
|
||||
S storage c;
|
||||
assembly {
|
||||
switch a
|
||||
|
@ -1,20 +1,14 @@
|
||||
contract C {
|
||||
struct S { bool f; }
|
||||
S s;
|
||||
function f(uint256 a) internal pure returns (S storage c) {
|
||||
assembly {
|
||||
switch a
|
||||
default { c_slot := s_slot }
|
||||
}
|
||||
}
|
||||
function g(bool flag) internal pure returns (S storage c) {
|
||||
function f(bool flag) internal pure returns (S storage c) {
|
||||
assembly {
|
||||
switch flag
|
||||
case 0 { c_slot := s_slot }
|
||||
default { c_slot := s_slot }
|
||||
}
|
||||
}
|
||||
function h(uint256 a) internal pure returns (S storage c) {
|
||||
function g(uint256 a) internal pure returns (S storage c) {
|
||||
assembly {
|
||||
switch a
|
||||
case 0 { revert(0, 0) }
|
||||
|
@ -0,0 +1,12 @@
|
||||
contract C {
|
||||
struct S { bool f; }
|
||||
S s;
|
||||
function f(uint256 a) internal pure returns (S storage c) {
|
||||
assembly {
|
||||
switch a
|
||||
default { c_slot := s_slot }
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (142-195): "switch" statement with only a default case.
|
@ -87,12 +87,12 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(
|
||||
shared_ptr<Object> parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false);
|
||||
if (!parserResult)
|
||||
return {};
|
||||
if (!parserResult->code || !errorReporter.errors().empty())
|
||||
if (!parserResult->code || errorReporter.hasErrors())
|
||||
return {};
|
||||
shared_ptr<AsmAnalysisInfo> analysisInfo = make_shared<AsmAnalysisInfo>();
|
||||
AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->dataNames());
|
||||
// TODO this should be done recursively.
|
||||
if (!analyzer.analyze(*parserResult->code) || !errorReporter.errors().empty())
|
||||
if (!analyzer.analyze(*parserResult->code) || errorReporter.hasErrors())
|
||||
return {};
|
||||
return {std::move(parserResult->code), std::move(analysisInfo)};
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ BOOST_FIXTURE_TEST_CASE(if_statement_custom_weights, CustomWeightFixture)
|
||||
BOOST_AUTO_TEST_CASE(switch_statement_tiny)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(codeSize(
|
||||
"{ switch calldatasize() default {} }"
|
||||
"{ switch calldatasize() case 0 {} }"
|
||||
), 4);
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c
|
||||
ErrorList errors;
|
||||
soltestAssert(m_dialect, "");
|
||||
std::tie(m_ast, m_analysisInfo) = yul::test::parse(m_source, *m_dialect, errors);
|
||||
if (!m_ast || !m_analysisInfo || !errors.empty())
|
||||
if (!m_ast || !m_analysisInfo || !Error::containsOnlyWarnings(errors))
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
printErrors(_stream, errors);
|
||||
|
@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position
|
||||
BOOST_TEST(mutatedChromosome.length() > chromosome.length());
|
||||
|
||||
vector<string> suffix(
|
||||
mutatedChromosome.optimisationSteps().end() - chromosome.length(),
|
||||
mutatedChromosome.optimisationSteps().end() - static_cast<ptrdiff_t>(chromosome.length()),
|
||||
mutatedChromosome.optimisationSteps().end()
|
||||
);
|
||||
BOOST_TEST(suffix == chromosome.optimisationSteps());
|
||||
@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_after_last_position)
|
||||
|
||||
vector<string> prefix(
|
||||
mutatedChromosome.optimisationSteps().begin(),
|
||||
mutatedChromosome.optimisationSteps().begin() + chromosome.length()
|
||||
mutatedChromosome.optimisationSteps().begin() + static_cast<ptrdiff_t>(chromosome.length())
|
||||
);
|
||||
BOOST_TEST(prefix == chromosome.optimisationSteps());
|
||||
}
|
||||
@ -179,8 +179,8 @@ BOOST_AUTO_TEST_CASE(alternativeMutations_should_choose_between_mutations_with_g
|
||||
for (size_t i = 0; i < 10; ++i)
|
||||
{
|
||||
Chromosome mutatedChromosome = mutation(chromosome);
|
||||
cCount += static_cast<int>(mutatedChromosome == Chromosome("c"));
|
||||
fCount += static_cast<int>(mutatedChromosome == Chromosome("f"));
|
||||
cCount += (mutatedChromosome == Chromosome("c") ? 1 : 0);
|
||||
fCount += (mutatedChromosome == Chromosome("f") ? 1 : 0);
|
||||
}
|
||||
|
||||
// This particular seed results in 7 "c"s out of 10 which looks plausible given the 80% chance.
|
||||
|
@ -135,7 +135,7 @@ BOOST_FIXTURE_TEST_CASE(makeRandom_should_get_chromosome_lengths_from_specified_
|
||||
size_t maxLength = 5;
|
||||
assert(chromosomeCount % maxLength == 0);
|
||||
|
||||
auto nextLength = [counter = 0, maxLength]() mutable { return counter++ % maxLength; };
|
||||
auto nextLength = [counter = 0ul, maxLength]() mutable { return counter++ % maxLength; };
|
||||
auto population = Population::makeRandom(m_fitnessMetric, chromosomeCount, nextLength);
|
||||
|
||||
// We can't rely on the order since the population sorts its chromosomes immediately but
|
||||
|
@ -72,9 +72,13 @@ size_t phaser::test::countDifferences(Chromosome const& _chromosome1, Chromosome
|
||||
{
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < min(_chromosome1.length(), _chromosome2.length()); ++i)
|
||||
count += static_cast<int>(_chromosome1.optimisationSteps()[i] != _chromosome2.optimisationSteps()[i]);
|
||||
if (_chromosome1.optimisationSteps()[i] != _chromosome2.optimisationSteps()[i])
|
||||
++count;
|
||||
|
||||
return count + abs(static_cast<int>(_chromosome1.length() - _chromosome2.length()));
|
||||
return count + static_cast<size_t>(abs(
|
||||
static_cast<long>(_chromosome1.length()) -
|
||||
static_cast<long>(_chromosome2.length())
|
||||
));
|
||||
}
|
||||
|
||||
TemporaryDirectory::TemporaryDirectory(std::string const& _prefix):
|
||||
|
@ -155,7 +155,7 @@ Population ClassicGeneticAlgorithm::select(Population _population, size_t _selec
|
||||
vector<Individual> selectedIndividuals;
|
||||
for (size_t i = 0; i < _selectionSize; ++i)
|
||||
{
|
||||
uint32_t ball = SimulationRNG::uniformInt(0, rouletteRange - 1);
|
||||
size_t ball = SimulationRNG::uniformInt(0, rouletteRange - 1);
|
||||
|
||||
size_t cumulativeFitness = 0;
|
||||
for (auto const& individual: _population.individuals())
|
||||
|
@ -126,12 +126,12 @@ ChromosomePair fixedPointSwap(
|
||||
|
||||
return {
|
||||
Chromosome(
|
||||
vector<string>(begin1, begin1 + _crossoverPoint) +
|
||||
vector<string>(begin2 + _crossoverPoint, end2)
|
||||
vector<string>(begin1, begin1 + static_cast<ptrdiff_t>(_crossoverPoint)) +
|
||||
vector<string>(begin2 + static_cast<ptrdiff_t>(_crossoverPoint), end2)
|
||||
),
|
||||
Chromosome(
|
||||
vector<string>(begin2, begin2 + _crossoverPoint) +
|
||||
vector<string>(begin1 + _crossoverPoint, end1)
|
||||
vector<string>(begin2, begin2 + static_cast<ptrdiff_t>(_crossoverPoint)) +
|
||||
vector<string>(begin1 + static_cast<ptrdiff_t>(_crossoverPoint), end1)
|
||||
),
|
||||
};
|
||||
}
|
||||
@ -196,8 +196,8 @@ ChromosomePair fixedTwoPointSwap(
|
||||
assert(_crossoverPoint2 <= _chromosome1.length());
|
||||
assert(_crossoverPoint2 <= _chromosome2.length());
|
||||
|
||||
size_t lowPoint = min(_crossoverPoint1, _crossoverPoint2);
|
||||
size_t highPoint = max(_crossoverPoint1, _crossoverPoint2);
|
||||
auto lowPoint = static_cast<ptrdiff_t>(min(_crossoverPoint1, _crossoverPoint2));
|
||||
auto highPoint = static_cast<ptrdiff_t>(max(_crossoverPoint1, _crossoverPoint2));
|
||||
|
||||
auto begin1 = _chromosome1.optimisationSteps().begin();
|
||||
auto begin2 = _chromosome2.optimisationSteps().begin();
|
||||
@ -282,17 +282,17 @@ ChromosomePair uniformSwap(Chromosome const& _chromosome1, Chromosome const& _ch
|
||||
if (_chromosome1.length() > minLength)
|
||||
{
|
||||
if (swapTail)
|
||||
steps2.insert(steps2.end(), begin1 + minLength, end1);
|
||||
steps2.insert(steps2.end(), begin1 + static_cast<ptrdiff_t>(minLength), end1);
|
||||
else
|
||||
steps1.insert(steps1.end(), begin1 + minLength, end1);
|
||||
steps1.insert(steps1.end(), begin1 + static_cast<ptrdiff_t>(minLength), end1);
|
||||
}
|
||||
|
||||
if (_chromosome2.length() > minLength)
|
||||
{
|
||||
if (swapTail)
|
||||
steps1.insert(steps1.end(), begin2 + minLength, end2);
|
||||
steps1.insert(steps1.end(), begin2 + static_cast<ptrdiff_t>(minLength), end2);
|
||||
else
|
||||
steps2.insert(steps2.end(), begin2 + minLength, end2);
|
||||
steps2.insert(steps2.end(), begin2 + static_cast<ptrdiff_t>(minLength), end2);
|
||||
}
|
||||
|
||||
return {Chromosome(steps1), Chromosome(steps2)};
|
||||
|
@ -30,7 +30,7 @@ vector<tuple<size_t, size_t>> RandomPairSelection::materialise(size_t _poolSize)
|
||||
if (_poolSize < 2)
|
||||
return {};
|
||||
|
||||
size_t count = static_cast<size_t>(round(_poolSize * m_selectionSize));
|
||||
auto count = static_cast<size_t>(round(_poolSize * m_selectionSize));
|
||||
|
||||
vector<tuple<size_t, size_t>> selection;
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
@ -64,7 +64,10 @@ vector<tuple<size_t, size_t>> PairsFromRandomSubset::materialise(size_t _poolSiz
|
||||
} while (selectedIndices.size() % 2 != 0);
|
||||
}
|
||||
else
|
||||
selectedIndices.erase(selectedIndices.begin() + SimulationRNG::uniformInt(0, selectedIndices.size() - 1));
|
||||
selectedIndices.erase(
|
||||
selectedIndices.begin() +
|
||||
static_cast<ptrdiff_t>(SimulationRNG::uniformInt(0, selectedIndices.size() - 1))
|
||||
);
|
||||
}
|
||||
assert(selectedIndices.size() % 2 == 0);
|
||||
|
||||
@ -73,14 +76,14 @@ vector<tuple<size_t, size_t>> PairsFromRandomSubset::materialise(size_t _poolSiz
|
||||
{
|
||||
size_t position1 = SimulationRNG::uniformInt(0, selectedIndices.size() - 1);
|
||||
size_t value1 = selectedIndices[position1];
|
||||
selectedIndices.erase(selectedIndices.begin() + position1);
|
||||
selectedIndices.erase(selectedIndices.begin() + static_cast<ptrdiff_t>(position1));
|
||||
size_t position2 = SimulationRNG::uniformInt(0, selectedIndices.size() - 1);
|
||||
size_t value2 = selectedIndices[position2];
|
||||
selectedIndices.erase(selectedIndices.begin() + position2);
|
||||
selectedIndices.erase(selectedIndices.begin() + static_cast<ptrdiff_t>(position2));
|
||||
|
||||
selectedPairs.push_back({value1, value2});
|
||||
selectedPairs.emplace_back(value1, value2);
|
||||
}
|
||||
assert(selectedIndices.size() == 0);
|
||||
assert(selectedIndices.empty());
|
||||
|
||||
return selectedPairs;
|
||||
}
|
||||
|
@ -17,12 +17,17 @@
|
||||
|
||||
#include <tools/yulPhaser/SimulationRNG.h>
|
||||
|
||||
// NOTE: The code would work with std::random but the results for a given seed would not be reproducible
|
||||
// across different STL implementations. Boost does not guarantee this either but at least it has only one
|
||||
// implementation. Reproducibility is not a hard requirement for yul-phaser but it's nice to have.
|
||||
#include <boost/random/bernoulli_distribution.hpp>
|
||||
#include <boost/random/binomial_distribution.hpp>
|
||||
#include <boost/random/uniform_int_distribution.hpp>
|
||||
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::phaser;
|
||||
|
||||
@ -30,23 +35,27 @@ thread_local boost::random::mt19937 SimulationRNG::s_generator(SimulationRNG::ge
|
||||
|
||||
bool SimulationRNG::bernoulliTrial(double _successProbability)
|
||||
{
|
||||
boost::random::bernoulli_distribution<> distribution(_successProbability);
|
||||
boost::random::bernoulli_distribution<double> distribution(_successProbability);
|
||||
|
||||
return static_cast<bool>(distribution(s_generator));
|
||||
}
|
||||
|
||||
uint32_t SimulationRNG::uniformInt(uint32_t _min, uint32_t _max)
|
||||
{
|
||||
boost::random::uniform_int_distribution<> distribution(_min, _max);
|
||||
return distribution(s_generator);
|
||||
}
|
||||
|
||||
uint32_t SimulationRNG::binomialInt(uint32_t _numTrials, double _successProbability)
|
||||
size_t SimulationRNG::uniformInt(size_t _min, size_t _max)
|
||||
{
|
||||
boost::random::binomial_distribution<> distribution(_numTrials, _successProbability);
|
||||
boost::random::uniform_int_distribution<size_t> distribution(_min, _max);
|
||||
return distribution(s_generator);
|
||||
}
|
||||
|
||||
size_t SimulationRNG::binomialInt(size_t _numTrials, double _successProbability)
|
||||
{
|
||||
// NOTE: binomial_distribution<size_t> would not work because it internally tries to use abs()
|
||||
// and fails to compile due to ambiguous conversion.
|
||||
assert(_numTrials <= static_cast<size_t>(numeric_limits<long>::max()));
|
||||
|
||||
boost::random::binomial_distribution<long> distribution(static_cast<long>(_numTrials), _successProbability);
|
||||
return static_cast<size_t>(distribution(s_generator));
|
||||
}
|
||||
|
||||
uint32_t SimulationRNG::generateSeed()
|
||||
{
|
||||
// This is not a secure way to seed the generator but it's good enough for simulation purposes.
|
||||
|
@ -38,8 +38,8 @@ class SimulationRNG
|
||||
{
|
||||
public:
|
||||
static bool bernoulliTrial(double _successProbability);
|
||||
static uint32_t uniformInt(uint32_t _min, uint32_t _max);
|
||||
static uint32_t binomialInt(uint32_t _numTrials, double _successProbability);
|
||||
static size_t uniformInt(size_t _min, size_t _max);
|
||||
static size_t binomialInt(size_t _numTrials, double _successProbability);
|
||||
|
||||
/// Resets generator to a known state given by the @a seed. Given the same seed, a fixed
|
||||
/// sequence of calls to the members generating random values is guaranteed to produce the
|
||||
|
Loading…
Reference in New Issue
Block a user