aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--CMakeLists.txt2
-rw-r--r--Changelog.md7
-rw-r--r--appveyor.yml2
-rw-r--r--cmake/EthBuildInfo.cmake2
-rw-r--r--cmake/EthCheckCXXCompilerFlag.cmake23
-rw-r--r--cmake/EthCompilerSettings.cmake23
-rw-r--r--cmake/EthDependencies.cmake7
-rw-r--r--docs/abi-spec.rst19
-rw-r--r--docs/common-patterns.rst4
-rw-r--r--docs/contracts.rst2
-rw-r--r--docs/contributing.rst6
-rw-r--r--docs/frequently-asked-questions.rst4
-rw-r--r--docs/miscellaneous.rst6
-rw-r--r--docs/units-and-global-variables.rst6
-rw-r--r--libdevcore/Exceptions.cpp10
-rw-r--r--libevmasm/AssemblyItem.cpp4
-rw-r--r--libevmasm/CMakeLists.txt2
-rw-r--r--libevmasm/EVMSchedule.h62
-rw-r--r--libevmasm/Instruction.h18
-rw-r--r--libevmasm/SemanticInformation.cpp4
-rw-r--r--liblll/CodeFragment.cpp97
-rw-r--r--liblll/CodeFragment.h7
-rw-r--r--liblll/Compiler.cpp9
-rw-r--r--liblll/Compiler.h6
-rw-r--r--liblll/CompilerState.cpp2
-rw-r--r--libsolidity/analysis/GlobalContext.cpp67
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp5
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp9
-rw-r--r--libsolidity/analysis/TypeChecker.cpp51
-rw-r--r--libsolidity/analysis/TypeChecker.h4
-rw-r--r--libsolidity/ast/Types.cpp53
-rw-r--r--libsolidity/ast/Types.h2
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp38
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp25
-rw-r--r--libsolidity/codegen/CompilerUtils.h35
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp116
-rw-r--r--libsolidity/formal/Z3Interface.cpp9
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp6
-rw-r--r--libsolidity/interface/GasEstimator.cpp2
-rw-r--r--libsolidity/parsing/Parser.cpp1
-rw-r--r--lllc/main.cpp4
-rwxr-xr-xscripts/install_deps.sh17
-rwxr-xr-xscripts/tests.sh4
-rw-r--r--test/RPCSession.cpp6
-rw-r--r--test/TestHelper.cpp2
-rw-r--r--test/TestHelper.h1
-rw-r--r--test/boostTest.cpp19
-rw-r--r--test/liblll/Compiler.cpp128
-rw-r--r--test/liblll/EndToEndTest.cpp86
-rw-r--r--test/libsolidity/AnalysisFramework.cpp45
-rw-r--r--test/libsolidity/AnalysisFramework.h11
-rw-r--r--test/libsolidity/GasMeter.cpp10
-rw-r--r--test/libsolidity/SMTChecker.cpp86
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp87
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp150
57 files changed, 1033 insertions, 389 deletions
diff --git a/.travis.yml b/.travis.yml
index c30e3e0f..708d3620 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -49,13 +49,6 @@ env:
matrix:
include:
- # Ubuntu 14.04 LTS "Trusty Tahr"
- # https://en.wikipedia.org/wiki/List_of_Ubuntu_releases#Ubuntu_14.04_LTS_.28Trusty_Tahr.29
- #
- # TravisCI doesn't directly support any new Ubuntu releases. These is
- # some Docker support, which we should probably investigate, at least for
- # Ubuntu 16.04 LTS "Xenial Xerus"
- # See https://en.wikipedia.org/wiki/List_of_Ubuntu_releases#Ubuntu_16.04_LTS_.28Xenial_Xerus.29.
- os: linux
dist: trusty
sudo: required
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8f71cedc..537a9521 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,7 @@ string(REGEX MATCHALL ".." LICENSE_TEXT "${LICENSE_TEXT}")
string(REGEX REPLACE ";" ",\n\t0x" LICENSE_TEXT "${LICENSE_TEXT}")
set(LICENSE_TEXT "0x${LICENSE_TEXT}")
-configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" "license.h")
+configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" include/license.h)
include(EthOptions)
configure_project(TESTS)
diff --git a/Changelog.md b/Changelog.md
index 9755d2d3..8ebc30d0 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,8 +2,15 @@
Features:
* Parser: Better error message for unexpected trailing comma in parameter lists.
+ * Syntax Checker: Unary ``+`` is now a syntax error as experimental 0.5.0 feature.
+ * Type Checker: Disallow non-pure constant state variables as experimental 0.5.0 feature.
Bugfixes:
+ * Parser: Fix source location of VariableDeclarationStatement.
+ * Type Checker: Properly check array length and don't rely on an assertion in code generation.
+ * Type Checker: Properly support overwriting members inherited from ``address`` in a contract
+ (such as ``balance``, ``transfer``, etc.)
+ * Type Checker: Prevent duplicate event declarations.
### 0.4.17 (2017-09-21)
diff --git a/appveyor.yml b/appveyor.yml
index 3d4d65bb..b50681b9 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -71,7 +71,7 @@ build_script:
test_script:
- cd %APPVEYOR_BUILD_FOLDER%
- cd %APPVEYOR_BUILD_FOLDER%\build\test\%CONFIGURATION%
- - soltest.exe --show-progress -- --no-ipc
+ - soltest.exe --show-progress -- --no-ipc --no-smt
artifacts:
- path: solidity-windows.zip
diff --git a/cmake/EthBuildInfo.cmake b/cmake/EthBuildInfo.cmake
index 1f70d371..cae3e5ce 100644
--- a/cmake/EthBuildInfo.cmake
+++ b/cmake/EthBuildInfo.cmake
@@ -39,5 +39,5 @@ function(create_build_info NAME)
-DPROJECT_VERSION="${PROJECT_VERSION}"
-P "${ETH_SCRIPTS_DIR}/buildinfo.cmake"
)
- include_directories(BEFORE ${PROJECT_BINARY_DIR})
+ include_directories("${PROJECT_BINARY_DIR}/include")
endfunction()
diff --git a/cmake/EthCheckCXXCompilerFlag.cmake b/cmake/EthCheckCXXCompilerFlag.cmake
new file mode 100644
index 00000000..c6ed35b4
--- /dev/null
+++ b/cmake/EthCheckCXXCompilerFlag.cmake
@@ -0,0 +1,23 @@
+include(CheckCXXCompilerFlag)
+
+# Adds CXX compiler flag if the flag is supported by the compiler.
+#
+# This is effectively a combination of CMake's check_cxx_compiler_flag()
+# and add_compile_options():
+#
+# if(check_cxx_compiler_flag(flag))
+# add_compile_options(flag)
+#
+function(eth_add_cxx_compiler_flag_if_supported FLAG)
+ # Remove leading - or / from the flag name.
+ string(REGEX REPLACE "^-|/" "" name ${FLAG})
+ check_cxx_compiler_flag(${FLAG} ${name})
+ if(${name})
+ add_compile_options(${FLAG})
+ endif()
+
+ # If the optional argument passed, store the result there.
+ if(ARGV1)
+ set(${ARGV1} ${name} PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake
index 1a00ae70..6d4dadeb 100644
--- a/cmake/EthCompilerSettings.cmake
+++ b/cmake/EthCompilerSettings.cmake
@@ -4,7 +4,7 @@
# CMake file for cpp-ethereum project which specifies our compiler settings
# for each supported platform and build configuration.
#
-# See http://www.ethdocs.org/en/latest/ethereum-clients/cpp-ethereum/.
+# The documentation for cpp-ethereum is hosted at http://cpp-ethereum.org
#
# Copyright (c) 2014-2016 cpp-ethereum contributors.
#------------------------------------------------------------------------------
@@ -14,18 +14,15 @@
#
# These settings then end up spanning all POSIX platforms (Linux, OS X, BSD, etc)
-include(CheckCXXCompilerFlag)
+include(EthCheckCXXCompilerFlag)
-check_cxx_compiler_flag(-fstack-protector-strong have_stack_protector_strong)
-if (have_stack_protector_strong)
- add_compile_options(-fstack-protector-strong)
-else()
- check_cxx_compiler_flag(-fstack-protector have_stack_protector)
- if(have_stack_protector)
- add_compile_options(-fstack-protector)
- endif()
+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()
+eth_add_cxx_compiler_flag_if_supported(-Wimplicit-fallthrough)
+
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
# Use ISO C++11 standard language.
@@ -83,12 +80,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA
message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
endif ()
- # Until https://github.com/ethereum/solidity/issues/2479 is handled
- # disable all implicit fallthrough warnings in the codebase for GCC > 7.0
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
- add_compile_options(-Wno-implicit-fallthrough)
- endif()
-
# Additional Clang-specific compiler settings.
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake
index 1204f186..233ac22a 100644
--- a/cmake/EthDependencies.cmake
+++ b/cmake/EthDependencies.cmake
@@ -48,10 +48,3 @@ option(Boost_USE_STATIC_LIBS "Link Boost statically" ON)
find_package(Boost 1.54.0 QUIET REQUIRED COMPONENTS regex filesystem unit_test_framework program_options system)
eth_show_dependency(Boost boost)
-
-if (APPLE)
- link_directories(/usr/local/lib)
- include_directories(/usr/local/include)
-endif()
-
-include_directories(BEFORE "${PROJECT_BINARY_DIR}/include")
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index 29d98645..0361458f 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -442,3 +442,22 @@ would result in the JSON:
"outputs": []
}
]
+
+.. _abi_packed_mode:
+
+Non-standard Packed Mode
+========================
+
+Solidity supports a non-standard packed mode where:
+
+- no :ref:`function selector <abi_function_selector>` is encoded,
+- short types are not zero padded and
+- dynamic types are encoded in-place and without the length.
+
+As an example encoding ``uint1, bytes1, uint8, string`` with values ``1, 0x42, 0x2424, "Hello, world!"`` results in ::
+
+ 0x0142242448656c6c6f2c20776f726c6421
+ ^^ uint1(1)
+ ^^ bytes1(0x42)
+ ^^^^ uint8(0x2424)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ string("Hello, world!") without a length field
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst
index acef13b7..52319be0 100644
--- a/docs/common-patterns.rst
+++ b/docs/common-patterns.rst
@@ -93,7 +93,7 @@ Notice that, in this example, an attacker could trap the
contract into an unusable state by causing ``richest`` to be
the address of a contract that has a fallback function
which fails (e.g. by using ``revert()`` or by just
-conssuming more than the 2300 gas stipend). That way,
+consuming more than the 2300 gas stipend). That way,
whenever ``transfer`` is called to deliver funds to the
"poisoned" contract, it will fail and thus also ``becomeRichest``
will fail, with the contract being stuck forever.
@@ -121,7 +121,7 @@ unless you declare make your state variables ``public``.
Furthermore, you can restrict who can make modifications
to your contract's state or call your contract's
-functions and this is what this page is about.
+functions and this is what this section is about.
.. index:: function;modifier
diff --git a/docs/contracts.rst b/docs/contracts.rst
index 69600fc1..cdc92315 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -20,7 +20,7 @@ Contracts can be created "from outside" via Ethereum transactions or from within
IDEs, such as `Remix <https://remix.ethereum.org/>`_, make the creation process seamless using UI elements.
-Creating contracts programatically on Ethereum is best done via using the JavaScript API `web3.js <https://github.com/etherem/web3.js>`_.
+Creating contracts programatically on Ethereum is best done via using the JavaScript API `web3.js <https://github.com/ethereum/web3.js>`_.
As of today it has a method called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_
to facilitate contract creation.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 01caa5b1..0f7c3e72 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -64,9 +64,11 @@ Running the compiler tests
==========================
Solidity includes different types of tests. They are included in the application
-called ``soltest``. Some of them require the ``cpp-ethereum`` client in testing mode.
+called ``soltest``. Some of them require the ``cpp-ethereum`` client in testing mode,
+some others require ``libz3`` to be installed.
-To run a subset of the tests that do not require ``cpp-ethereum``, use ``./build/test/soltest -- --no-ipc``.
+To disable the z3 tests, use ``./build/test/soltest -- --no-smt`` and
+to run a subset of the tests that do not require ``cpp-ethereum``, use ``./build/test/soltest -- --no-ipc``.
For all other tests, you need to install `cpp-ethereum <https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/eth>`_ and run it in testing mode: ``eth --test -d /tmp/testeth``.
diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst
index 93dcfbb8..5c427c69 100644
--- a/docs/frequently-asked-questions.rst
+++ b/docs/frequently-asked-questions.rst
@@ -432,12 +432,12 @@ What happens to a ``struct``'s mapping when copying over a ``struct``?
This is a very interesting question. Suppose that we have a contract field set up like such::
struct user {
- mapping(string => address) usedContracts;
+ mapping(string => string) comments;
}
function somefunction {
user user1;
- user1.usedContracts["Hello"] = "World";
+ user1.comments["Hello"] = "World";
user user2 = user1;
}
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 6d6c25ac..6c0efa9e 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -322,10 +322,10 @@ Global Variables
- ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error)
- ``require(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component)
- ``revert()``: abort execution and revert state changes
-- ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
+- ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
- ``sha3(...) returns (bytes32)``: an alias to ``keccak256``
-- ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments
-- ``ripemd160(...) returns (bytes20)``: compute the RIPEMD-160 hash of the (tightly packed) arguments
+- ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
+- ``ripemd160(...) returns (bytes20)``: compute the RIPEMD-160 hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
- ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error
- ``addmod(uint x, uint y, uint k) returns (uint)``: compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``
- ``mulmod(uint x, uint y, uint k) returns (uint)``: compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index 887535da..7af97376 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -116,13 +116,13 @@ Mathematical and Cryptographic Functions
``mulmod(uint x, uint y, uint k) returns (uint)``:
compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``.
``keccak256(...) returns (bytes32)``:
- compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
+ compute the Ethereum-SHA-3 (Keccak-256) hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
``sha256(...) returns (bytes32)``:
- compute the SHA-256 hash of the (tightly packed) arguments
+ compute the SHA-256 hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
``sha3(...) returns (bytes32)``:
alias to ``keccak256``
``ripemd160(...) returns (bytes20)``:
- compute RIPEMD-160 hash of the (tightly packed) arguments
+ compute RIPEMD-160 hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``:
recover the address associated with the public key from elliptic curve signature or return zero on error
(`example usage <https://ethereum.stackexchange.com/q/1777/222>`_)
diff --git a/libdevcore/Exceptions.cpp b/libdevcore/Exceptions.cpp
index f422d926..f204dbc2 100644
--- a/libdevcore/Exceptions.cpp
+++ b/libdevcore/Exceptions.cpp
@@ -24,10 +24,14 @@ using namespace dev;
char const* Exception::what() const noexcept
{
+ // Return the comment if available.
if (string const* cmt = comment())
- return cmt->c_str();
- else
- return nullptr;
+ return cmt->data();
+
+ // Fallback to base what().
+ // Boost accepts nullptr, but the C++ standard doesn't
+ // and crashes on some platforms.
+ return std::exception::what();
}
string Exception::lineInfo() const
diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp
index cfe91be0..64963021 100644
--- a/libevmasm/AssemblyItem.cpp
+++ b/libevmasm/AssemblyItem.cpp
@@ -17,8 +17,6 @@
#include <libevmasm/AssemblyItem.h>
-#include <libevmasm/SemanticInformation.h>
-
#include <libdevcore/CommonData.h>
#include <libdevcore/FixedHash.h>
@@ -112,7 +110,7 @@ bool AssemblyItem::canBeFunctional() const
switch (m_type)
{
case Operation:
- return !SemanticInformation::isDupInstruction(*this) && !SemanticInformation::isSwapInstruction(*this);
+ return !isDupInstruction(instruction()) && !isSwapInstruction(instruction());
case Push:
case PushString:
case PushTag:
diff --git a/libevmasm/CMakeLists.txt b/libevmasm/CMakeLists.txt
index 5c945c7d..cfd59dff 100644
--- a/libevmasm/CMakeLists.txt
+++ b/libevmasm/CMakeLists.txt
@@ -2,4 +2,4 @@ file(GLOB sources "*.cpp")
file(GLOB headers "*.h")
add_library(evmasm ${sources} ${headers})
-target_link_libraries(evmasm PUBLIC devcore jsoncpp)
+target_link_libraries(evmasm PUBLIC jsoncpp devcore)
diff --git a/libevmasm/EVMSchedule.h b/libevmasm/EVMSchedule.h
deleted file mode 100644
index 1695a59c..00000000
--- a/libevmasm/EVMSchedule.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- This file is part of solidity.
-
- solidity is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- solidity is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with solidity. If not, see <http://www.gnu.org/licenses/>.
-*/
-/** @file EVMSchedule.h
- * @author Gav <i@gavwood.com>
- * @author Christian <c@ethdev.com>
- * @date 2015
- */
-
-#pragma once
-
-namespace dev
-{
-namespace solidity
-{
-
-struct EVMSchedule
-{
- unsigned stackLimit = 1024;
- unsigned expGas = 10;
- unsigned expByteGas = 10;
- unsigned keccak256Gas = 30;
- unsigned keccak256WordGas = 6;
- unsigned sloadGas = 200;
- unsigned sstoreSetGas = 20000;
- unsigned sstoreResetGas = 5000;
- unsigned sstoreRefundGas = 15000;
- unsigned jumpdestGas = 1;
- unsigned logGas = 375;
- unsigned logDataGas = 8;
- unsigned logTopicGas = 375;
- unsigned createGas = 32000;
- unsigned callGas = 40;
- unsigned callStipend = 2300;
- unsigned callValueTransferGas = 9000;
- unsigned callNewAccountGas = 25000;
- unsigned selfdestructRefundGas = 24000;
- unsigned memoryGas = 3;
- unsigned quadCoeffDiv = 512;
- unsigned createDataGas = 200;
- unsigned txGas = 21000;
- unsigned txCreateGas = 53000;
- unsigned txDataZeroGas = 4;
- unsigned txDataNonZeroGas = 68;
- unsigned copyGas = 3;
-};
-
-}
-}
diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h
index afbef71d..d9c53900 100644
--- a/libevmasm/Instruction.h
+++ b/libevmasm/Instruction.h
@@ -197,6 +197,24 @@ enum class Instruction: uint8_t
SELFDESTRUCT = 0xff ///< halt execution and register account for later deletion
};
+/// @returns true if the instruction is a PUSH
+inline bool isPushInstruction(Instruction _inst)
+{
+ return Instruction::PUSH1 <= _inst && _inst <= Instruction::PUSH32;
+}
+
+/// @returns true if the instruction is a DUP
+inline bool isDupInstruction(Instruction _inst)
+{
+ return Instruction::DUP1 <= _inst && _inst <= Instruction::DUP16;
+}
+
+/// @returns true if the instruction is a SWAP
+inline bool isSwapInstruction(Instruction _inst)
+{
+ return Instruction::SWAP1 <= _inst && _inst <= Instruction::SWAP16;
+}
+
/// @returns the number of PUSH Instruction _inst
inline unsigned getPushNumber(Instruction _inst)
{
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp
index ceb3fbdd..83cfe2c6 100644
--- a/libevmasm/SemanticInformation.cpp
+++ b/libevmasm/SemanticInformation.cpp
@@ -90,14 +90,14 @@ bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
{
if (_item.type() != Operation)
return false;
- return Instruction::DUP1 <= _item.instruction() && _item.instruction() <= Instruction::DUP16;
+ return solidity::isDupInstruction(_item.instruction());
}
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
{
if (_item.type() != Operation)
return false;
- return Instruction::SWAP1 <= _item.instruction() && _item.instruction() <= Instruction::SWAP16;
+ return solidity::isSwapInstruction(_item.instruction());
}
bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 254f436f..d4ef3888 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -47,7 +47,8 @@ void CodeFragment::finalise(CompilerState const& _cs)
}
}
-CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM)
+CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback const& _readFile, bool _allowASM):
+ m_readFile(_readFile)
{
/*
std::cout << "CodeFragment. Locals:";
@@ -103,7 +104,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS
{
bigint i = *_t.get<bigint*>();
if (i < 0 || i > bigint(u256(0) - 1))
- error<IntegerOutOfRange>();
+ error<IntegerOutOfRange>(toString(i));
m_asm.append((u256)i);
break;
}
@@ -113,6 +114,22 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS
}
}
+namespace
+{
+/// Returns true iff the instruction is valid as a function.
+bool validFunctionalInstruction(string us)
+{
+ auto it = c_instructions.find(us);
+ return !(
+ it == c_instructions.end() ||
+ solidity::isPushInstruction(it->second) ||
+ solidity::isDupInstruction(it->second) ||
+ solidity::isSwapInstruction(it->second) ||
+ it->second == solidity::Instruction::JUMPDEST
+ );
+}
+}
+
void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
if (_t.tag() == 0 && _t.empty())
@@ -157,7 +174,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
auto i = *++_t.begin();
if (i.tag())
- error<InvalidName>();
+ error<InvalidName>(toString(i));
if (i.which() == sp::utree_type::string_type)
{
auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
@@ -198,7 +215,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
int c = 0;
for (auto const& i: _t)
if (c++)
- m_asm.append(CodeFragment(i, _s, true).m_asm);
+ m_asm.append(CodeFragment(i, _s, m_readFile, true).m_asm);
}
else if (us == "INCLUDE")
{
@@ -207,10 +224,12 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
string fileName = firstAsString();
if (fileName.empty())
error<InvalidName>("Empty file name provided");
- string contents = contentsString(fileName);
+ if (!m_readFile)
+ error<InvalidName>("Import callback not present");
+ string contents = m_readFile(fileName);
if (contents.empty())
error<InvalidName>(std::string("File not found (or empty): ") + fileName);
- m_asm.append(CodeFragment::compile(contents, _s).m_asm);
+ m_asm.append(CodeFragment::compile(contents, _s, m_readFile).m_asm);
}
else if (us == "SET")
{
@@ -219,7 +238,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
int c = 0;
for (auto const& i: _t)
if (c++ == 2)
- m_asm.append(CodeFragment(i, _s, false).m_asm);
+ m_asm.append(CodeFragment(i, _s, m_readFile, false).m_asm);
m_asm.append((u256)varAddress(firstAsString(), true));
m_asm.append(Instruction::MSTORE);
}
@@ -244,7 +263,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
if (ii == 1)
{
if (i.tag())
- error<InvalidName>();
+ error<InvalidName>(toString(i));
if (i.which() == sp::utree_type::string_type)
{
auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>();
@@ -260,7 +279,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
if (_t.size() == 3)
{
/// NOTE: some compilers could do the assignment first if this is done in a single line
- CodeFragment code = CodeFragment(i, _s);
+ CodeFragment code = CodeFragment(i, _s, m_readFile);
_s.defs[n] = code;
}
else
@@ -301,13 +320,13 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
}
else if (ii == 1)
{
- pos = CodeFragment(i, _s);
+ pos = CodeFragment(i, _s, m_readFile);
if (pos.m_asm.deposit() != 1)
- error<InvalidDeposit>(us);
+ error<InvalidDeposit>(toString(i));
}
else if (i.tag() != 0)
{
- error<InvalidLiteral>();
+ error<InvalidLiteral>(toString(i));
}
else if (i.which() == sp::utree_type::string_type)
{
@@ -318,7 +337,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
bigint bi = *i.get<bigint*>();
if (bi < 0)
- error<IntegerOutOfRange>();
+ error<IntegerOutOfRange>(toString(i));
else
{
bytes tmp = toCompactBigEndian(bi);
@@ -327,7 +346,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
}
else
{
- error<InvalidLiteral>();
+ error<InvalidLiteral>(toString(i));
}
ii++;
@@ -380,9 +399,9 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
if (c++)
{
if (us == "LLL" && c == 1)
- code.push_back(CodeFragment(i, ns));
+ code.push_back(CodeFragment(i, ns, m_readFile));
else
- code.push_back(CodeFragment(i, _s));
+ code.push_back(CodeFragment(i, _s, m_readFile));
}
auto requireSize = [&](unsigned s) { if (code.size() != s) error<IncorrectParameterCount>(us); };
auto requireMinSize = [&](unsigned s) { if (code.size() < s) error<IncorrectParameterCount>(us); };
@@ -403,13 +422,13 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
//requireDeposit(i, 1);
cs.args[m.args[i]] = code[i];
}
- m_asm.append(CodeFragment(m.code, cs).m_asm);
+ m_asm.append(CodeFragment(m.code, cs, m_readFile).m_asm);
for (auto const& i: cs.defs)
_s.defs[i.first] = i.second;
for (auto const& i: cs.macros)
_s.macros.insert(i);
}
- else if (c_instructions.count(us))
+ else if (c_instructions.count(us) && validFunctionalInstruction(us))
{
auto it = c_instructions.find(us);
requireSize(instructionInfo(it->second).args);
@@ -514,6 +533,44 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.appendJump(begin);
m_asm << end.tag();
}
+ else if (us == "SWITCH")
+ {
+ requireMinSize(1);
+
+ bool hasDefault = (code.size() % 2 == 1);
+ int startDeposit = m_asm.deposit();
+ int targetDeposit = hasDefault ? code[code.size() - 1].m_asm.deposit() : 0;
+
+ // The conditions
+ AssemblyItems jumpTags;
+ for (unsigned i = 0; i < code.size() - 1; i += 2)
+ {
+ requireDeposit(i, 1);
+ m_asm.append(code[i].m_asm);
+ jumpTags.push_back(m_asm.appendJumpI());
+ }
+
+ // The default, if present
+ if (hasDefault)
+ m_asm.append(code[code.size() - 1].m_asm);
+
+ // The targets - appending in reverse makes the top case the most efficient.
+ if (code.size() > 1)
+ {
+ auto end = m_asm.appendJump();
+ for (int i = 2 * (code.size() / 2 - 1); i >= 0; i -= 2)
+ {
+ m_asm << jumpTags[i / 2].tag();
+ requireDeposit(i + 1, targetDeposit);
+ m_asm.append(code[i + 1].m_asm);
+ if (i != 0)
+ m_asm.appendJump(end);
+ }
+ m_asm << end.tag();
+ }
+
+ m_asm.setDeposit(startDeposit + targetDeposit);
+ }
else if (us == "ALLOC")
{
requireSize(1);
@@ -622,13 +679,13 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
}
}
-CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s)
+CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s, ReadCallback const& _readFile)
{
CodeFragment ret;
sp::utree o;
parseTreeLLL(_src, o);
if (!o.empty())
- ret = CodeFragment(o, _s);
+ ret = CodeFragment(o, _s, _readFile);
_s.treesToKill.push_back(o);
return ret;
}
diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h
index 95d21563..e5cac34e 100644
--- a/liblll/CodeFragment.h
+++ b/liblll/CodeFragment.h
@@ -39,10 +39,12 @@ struct CompilerState;
class CodeFragment
{
public:
+ using ReadCallback = std::function<std::string(std::string const&)>;
+
CodeFragment() {}
- CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false);
+ CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback const& _readFile, bool _allowASM = false);
- static CodeFragment compile(std::string const& _src, CompilerState& _s);
+ static CodeFragment compile(std::string const& _src, CompilerState& _s, ReadCallback const& _readFile);
/// Consolidates data and compiles code.
Assembly& assembly(CompilerState const& _cs) { finalise(_cs); return m_asm; }
@@ -60,6 +62,7 @@ private:
bool m_finalised = false;
Assembly m_asm;
+ ReadCallback m_readFile;
};
static const CodeFragment NullCodeFragment;
diff --git a/liblll/Compiler.cpp b/liblll/Compiler.cpp
index b69675aa..1638f69e 100644
--- a/liblll/Compiler.cpp
+++ b/liblll/Compiler.cpp
@@ -28,13 +28,14 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
-bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors)
+
+bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors, ReadCallback const& _readFile)
{
try
{
CompilerState cs;
cs.populateStandard();
- auto assembly = CodeFragment::compile(_src, cs).assembly(cs);
+ auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
if (_opt)
assembly = assembly.optimise(true);
bytes ret = assembly.assemble().bytecode;
@@ -66,13 +67,13 @@ bytes dev::eth::compileLLL(string const& _src, bool _opt, vector<string>* _error
return bytes();
}
-std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector<std::string>* _errors)
+std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector<std::string>* _errors, ReadCallback const& _readFile)
{
try
{
CompilerState cs;
cs.populateStandard();
- auto assembly = CodeFragment::compile(_src, cs).assembly(cs);
+ auto assembly = CodeFragment::compile(_src, cs, _readFile).assembly(cs);
if (_opt)
assembly = assembly.optimise(true);
string ret = assembly.assemblyString();
diff --git a/liblll/Compiler.h b/liblll/Compiler.h
index 04aa1e26..c3395b66 100644
--- a/liblll/Compiler.h
+++ b/liblll/Compiler.h
@@ -30,9 +30,11 @@ namespace dev
namespace eth
{
+using ReadCallback = std::function<std::string(std::string const&)>;
+
std::string parseLLL(std::string const& _src);
-std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr);
-bytes compileLLL(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr);
+std::string compileLLLToAsm(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
+bytes compileLLL(std::string const& _src, bool _opt = true, std::vector<std::string>* _errors = nullptr, ReadCallback const& _readFile = ReadCallback());
}
}
diff --git a/liblll/CompilerState.cpp b/liblll/CompilerState.cpp
index d53dec7e..c0e344b2 100644
--- a/liblll/CompilerState.cpp
+++ b/liblll/CompilerState.cpp
@@ -82,5 +82,5 @@ void CompilerState::populateStandard()
"(def 'shl (val shift) (mul val (exp 2 shift)))"
"(def 'shr (val shift) (div val (exp 2 shift)))"
"}";
- CodeFragment::compile(s, *this);
+ CodeFragment::compile(s, *this, CodeFragment::ReadCallback());
}
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index 62dbd394..fd39d860 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.cpp
@@ -34,44 +34,29 @@ namespace solidity
{
GlobalContext::GlobalContext():
-m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)),
- make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message)),
- make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
- make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
- make_shared<MagicVariableDeclaration>("suicide",
- make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
- make_shared<MagicVariableDeclaration>("selfdestruct",
- make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
- make_shared<MagicVariableDeclaration>("addmod",
- make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("mulmod",
- make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("sha3",
- make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("keccak256",
- make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("log0",
- make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
- make_shared<MagicVariableDeclaration>("log1",
- make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
- make_shared<MagicVariableDeclaration>("log2",
- make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
- make_shared<MagicVariableDeclaration>("log3",
- make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
- make_shared<MagicVariableDeclaration>("log4",
- make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
- make_shared<MagicVariableDeclaration>("sha256",
- make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA256, true, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("ecrecover",
- make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("ripemd160",
- make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("assert",
- make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("require",
- make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("revert",
- make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure))})
+m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
+ make_shared<MagicVariableDeclaration>("addmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("assert", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)),
+ make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
+ make_shared<MagicVariableDeclaration>("log1", make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
+ make_shared<MagicVariableDeclaration>("log2", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
+ make_shared<MagicVariableDeclaration>("log3", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
+ make_shared<MagicVariableDeclaration>("log4", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
+ make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message)),
+ make_shared<MagicVariableDeclaration>("mulmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
+ make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
+ make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA256, true, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
+ make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
+ make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction))
+})
{
}
@@ -92,8 +77,7 @@ vector<Declaration const*> GlobalContext::declarations() const
MagicVariableDeclaration const* GlobalContext::currentThis() const
{
if (!m_thisPointer[m_currentContract])
- m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(
- "this", make_shared<ContractType>(*m_currentContract));
+ m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("this", make_shared<ContractType>(*m_currentContract));
return m_thisPointer[m_currentContract].get();
}
@@ -101,8 +85,7 @@ MagicVariableDeclaration const* GlobalContext::currentThis() const
MagicVariableDeclaration const* GlobalContext::currentSuper() const
{
if (!m_superPointer[m_currentContract])
- m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(
- "super", make_shared<ContractType>(*m_currentContract, true));
+ m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("super", make_shared<ContractType>(*m_currentContract, true));
return m_superPointer[m_currentContract].get();
}
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 8f07d43a..20016112 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -149,8 +149,10 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
if (!length->annotation().type)
ConstantEvaluator e(*length);
auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get());
- if (!lengthType || lengthType->isFractional())
+ if (!lengthType || !lengthType->mobileType())
fatalTypeError(length->location(), "Invalid array length, expected integer literal.");
+ else if (lengthType->isFractional())
+ fatalTypeError(length->location(), "Array with fractional length specified.");
else if (lengthType->isNegative())
fatalTypeError(length->location(), "Array with negative length specified.");
else
@@ -347,4 +349,3 @@ void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location,
m_errorOccurred = true;
m_errorReporter.fatalDeclarationError(_location, _description);
}
-
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp
index 187eb26f..0ca4b86c 100644
--- a/libsolidity/analysis/SyntaxChecker.cpp
+++ b/libsolidity/analysis/SyntaxChecker.cpp
@@ -182,8 +182,15 @@ bool SyntaxChecker::visit(Throw const& _throwStatement)
bool SyntaxChecker::visit(UnaryOperation const& _operation)
{
+ bool const v050 = m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeature::V050);
+
if (_operation.getOperator() == Token::Add)
- m_errorReporter.warning(_operation.location(), "Use of unary + is deprecated.");
+ {
+ if (v050)
+ m_errorReporter.syntaxError(_operation.location(), "Use of unary + is deprecated.");
+ else
+ m_errorReporter.warning(_operation.location(), "Use of unary + is deprecated.");
+ }
return true;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 4b2ec8d6..b2a88059 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -75,6 +75,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
ASTNode::listAccept(_contract.baseContracts(), *this);
checkContractDuplicateFunctions(_contract);
+ checkContractDuplicateEvents(_contract);
checkContractIllegalOverrides(_contract);
checkContractAbstractFunctions(_contract);
checkContractAbstractConstructors(_contract);
@@ -183,9 +184,27 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
msg
);
}
- for (auto const& it: functions)
+
+ findDuplicateDefinitions(functions, "Function with same name and arguments defined twice.");
+}
+
+void TypeChecker::checkContractDuplicateEvents(ContractDefinition const& _contract)
+{
+ /// Checks that two events with the same name defined in this contract have different
+ /// argument types
+ map<string, vector<EventDefinition const*>> events;
+ for (EventDefinition const* event: _contract.events())
+ events[event->name()].push_back(event);
+
+ findDuplicateDefinitions(events, "Event with same name and arguments defined twice.");
+}
+
+template <class T>
+void TypeChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions, string _message)
+{
+ for (auto const& it: _definitions)
{
- vector<FunctionDefinition const*> const& overloads = it.second;
+ vector<T> const& overloads = it.second;
set<size_t> reported;
for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
{
@@ -200,18 +219,17 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
if (ssl.infos.size() > 0)
{
- string msg = "Function with same name and arguments defined twice.";
size_t occurrences = ssl.infos.size();
if (occurrences > 32)
{
ssl.infos.resize(32);
- msg += " Truncated from " + boost::lexical_cast<string>(occurrences) + " to the first 32 occurrences.";
+ _message += " Truncated from " + boost::lexical_cast<string>(occurrences) + " to the first 32 occurrences.";
}
m_errorReporter.declarationError(
overloads[i]->location(),
ssl,
- msg
+ _message
);
}
}
@@ -627,14 +645,23 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
if (!allowed)
m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented.");
}
+
if (!_variable.value())
m_errorReporter.typeError(_variable.location(), "Uninitialized \"constant\" variable.");
else if (!_variable.value()->annotation().isPure)
- m_errorReporter.warning(
- _variable.value()->location(),
- "Initial value for constant variable has to be compile-time constant. "
- "This will fail to compile with the next breaking version change."
- );
+ {
+ if (_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ m_errorReporter.typeError(
+ _variable.value()->location(),
+ "Initial value for constant variable has to be compile-time constant."
+ );
+ else
+ m_errorReporter.warning(
+ _variable.value()->location(),
+ "Initial value for constant variable has to be compile-time constant. "
+ "This will fail to compile with the next breaking version change."
+ );
+ }
}
if (!_variable.isStateVariable())
{
@@ -1497,7 +1524,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
/* If no mobile type is available an error will be raised elsewhere. */
if (literal->mobileType())
m_errorReporter.warning(
- _functionCall.location(),
+ arguments[i]->location(),
"The type of \"" +
argType->toString() +
"\" was inferred as " +
@@ -1954,7 +1981,7 @@ void TypeChecker::endVisit(Literal const& _literal)
if (_literal.looksLikeAddress())
{
if (_literal.passesAddressChecksum())
- _literal.annotation().type = make_shared<IntegerType>(0, IntegerType::Modifier::Address);
+ _literal.annotation().type = make_shared<IntegerType>(160, IntegerType::Modifier::Address);
else
m_errorReporter.warning(
_literal.location(),
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index 0c6f54d3..abe6dac1 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -61,6 +61,7 @@ private:
/// Checks that two functions defined in this contract with the same name have different
/// arguments and that there is at most one constructor.
void checkContractDuplicateFunctions(ContractDefinition const& _contract);
+ void checkContractDuplicateEvents(ContractDefinition const& _contract);
void checkContractIllegalOverrides(ContractDefinition const& _contract);
/// Reports a type error with an appropiate message if overriden function signature differs.
/// Also stores the direct super function in the AST annotations.
@@ -108,6 +109,9 @@ private:
virtual void endVisit(ElementaryTypeNameExpression const& _expr) override;
virtual void endVisit(Literal const& _literal) override;
+ template <class T>
+ void findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions, std::string _message);
+
bool contractDependenciesAreCyclic(
ContractDefinition const& _contract,
std::set<ContractDefinition const*> const& _seenContracts = std::set<ContractDefinition const*>()
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 83a5b465..a3cbe50a 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -89,7 +89,7 @@ pair<u256, unsigned> const* StorageOffsets::offset(size_t _index) const
MemberList& MemberList::operator=(MemberList&& _other)
{
- assert(&_other != this);
+ solAssert(&_other != this, "");
m_memberTypes = move(_other.m_memberTypes);
m_storageOffsets = move(_other.m_storageOffsets);
@@ -203,7 +203,7 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
case Token::Byte:
return make_shared<FixedBytesType>(1);
case Token::Address:
- return make_shared<IntegerType>(0, IntegerType::Modifier::Address);
+ return make_shared<IntegerType>(160, IntegerType::Modifier::Address);
case Token::Bool:
return make_shared<BoolType>();
case Token::Bytes:
@@ -327,11 +327,11 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
m_bits(_bits), m_modifier(_modifier)
{
if (isAddress())
- m_bits = 160;
+ solAssert(m_bits == 160, "");
solAssert(
m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
"Invalid bit number for integer type: " + dev::toString(_bits)
- );
+ );
}
string IntegerType::identifier() const
@@ -1618,8 +1618,7 @@ string ContractType::canonicalName() const
MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) const
{
- // All address members and all interface functions
- MemberList::MemberMap members(IntegerType(120, IntegerType::Modifier::Address).nativeMembers(nullptr));
+ MemberList::MemberMap members;
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
@@ -1661,9 +1660,45 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) con
&it.second->declaration()
));
}
+ addNonConflictingAddressMembers(members);
return members;
}
+void ContractType::addNonConflictingAddressMembers(MemberList::MemberMap& _members)
+{
+ MemberList::MemberMap addressMembers = IntegerType(160, IntegerType::Modifier::Address).nativeMembers(nullptr);
+ for (auto const& addressMember: addressMembers)
+ {
+ bool clash = false;
+ for (auto const& member: _members)
+ {
+ if (
+ member.name == addressMember.name &&
+ (
+ // Members with different types are not allowed
+ member.type->category() != addressMember.type->category() ||
+ // Members must overload functions without clash
+ (
+ member.type->category() == Type::Category::Function &&
+ dynamic_cast<FunctionType const&>(*member.type).hasEqualArgumentTypes(dynamic_cast<FunctionType const&>(*addressMember.type))
+ )
+ )
+ )
+ {
+ clash = true;
+ break;
+ }
+ }
+
+ if (!clash)
+ _members.push_back(MemberList::Member(
+ addressMember.name,
+ addressMember.type,
+ addressMember.declaration
+ ));
+ }
+}
+
shared_ptr<FunctionType const> const& ContractType::newExpressionType() const
{
if (!m_constructorType)
@@ -2968,7 +3003,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
{
case Kind::Block:
return MemberList::MemberMap({
- {"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
+ {"coinbase", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
{"timestamp", make_shared<IntegerType>(256)},
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)},
{"difficulty", make_shared<IntegerType>(256)},
@@ -2977,7 +3012,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
});
case Kind::Message:
return MemberList::MemberMap({
- {"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
+ {"sender", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
{"gas", make_shared<IntegerType>(256)},
{"value", make_shared<IntegerType>(256)},
{"data", make_shared<ArrayType>(DataLocation::CallData)},
@@ -2985,7 +3020,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
});
case Kind::Transaction:
return MemberList::MemberMap({
- {"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
+ {"origin", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
{"gasprice", make_shared<IntegerType>(256)}
});
default:
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 8ba55521..ce29975e 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -716,6 +716,8 @@ public:
std::vector<std::tuple<VariableDeclaration const*, u256, unsigned>> stateVariables() const;
private:
+ static void addNonConflictingAddressMembers(MemberList::MemberMap& _members);
+
ContractDefinition const& m_contract;
/// If true, it is the "super" type of the current contract, i.e. it contains only inherited
/// members.
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index 9f6c55ba..756148e7 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -162,7 +162,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
break;
}
case Type::Category::Contract:
- templ("body", "cleaned := " + cleanupFunction(IntegerType(0, IntegerType::Modifier::Address)) + "(value)");
+ templ("body", "cleaned := " + cleanupFunction(IntegerType(160, IntegerType::Modifier::Address)) + "(value)");
break;
case Type::Category::Enum:
{
@@ -243,7 +243,7 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
toCategory == Type::Category::Integer ||
toCategory == Type::Category::Contract,
"");
- IntegerType const addressType(0, IntegerType::Modifier::Address);
+ IntegerType const addressType(160, IntegerType::Modifier::Address);
IntegerType const& to =
toCategory == Type::Category::Integer ?
dynamic_cast<IntegerType const&>(_to) :
@@ -487,6 +487,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
// TODO if this is not a byte array, we might just copy byte-by-byte anyway,
// because the encoding is position-independent, but we have to check that.
Whiskers templ(R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(start, length, pos) -> end {
<storeLength> // might update pos
<copyFun>(start, pos, length)
@@ -495,6 +496,8 @@ string ABIFunctions::abiEncodingFunctionCalldataArray(
)");
templ("storeLength", _to.isDynamicallySized() ? "mstore(pos, length) pos := add(pos, 0x20)" : "");
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("copyFun", copyToMemoryFunction(true));
templ("roundUpFun", roundUpFunction());
return templ.render();
@@ -527,6 +530,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
Whiskers templ(
dynamicBase ?
R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let length := <lengthFun>(value)
<storeLength> // might update pos
@@ -545,6 +549,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
}
)" :
R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let length := <lengthFun>(value)
<storeLength> // might update pos
@@ -560,6 +565,8 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
)"
);
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("return", dynamic ? " -> end " : "");
templ("assignEnd", dynamic ? "end := pos" : "");
templ("lengthFun", arrayLengthFunction(_from));
@@ -639,6 +646,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
{
solAssert(_to.isByteArray(), "");
Whiskers templ(R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) -> ret {
let slotValue := sload(value)
switch and(slotValue, 1)
@@ -665,6 +673,8 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
}
)");
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("arrayDataSlot", arrayDataAreaFunction(_from));
return templ.render();
}
@@ -681,6 +691,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
// more than desired, i.e. it writes beyond the end of memory.
Whiskers templ(
R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let length := <lengthFun>(value)
<storeLength> // might update pos
@@ -701,6 +712,8 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
)"
);
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("return", dynamic ? " -> end " : "");
templ("assignEnd", dynamic ? "end := pos" : "");
templ("lengthFun", arrayLengthFunction(_from));
@@ -748,6 +761,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
bool fromStorage = _from.location() == DataLocation::Storage;
bool dynamic = _to.isDynamicallyEncoded();
Whiskers templ(R"(
+ // <readableTypeNameFrom> -> <readableTypeNameTo>
function <functionName>(value, pos) <return> {
let tail := add(pos, <headSize>)
<init>
@@ -761,6 +775,8 @@ string ABIFunctions::abiEncodingFunctionStruct(
}
)");
templ("functionName", functionName);
+ templ("readableTypeNameFrom", _from.toString(true));
+ templ("readableTypeNameTo", _to.toString(true));
templ("return", dynamic ? " -> end " : "");
templ("assignEnd", dynamic ? "end := tail" : "");
// to avoid multiple loads from the same slot for subsequent members
@@ -995,9 +1011,11 @@ string ABIFunctions::shiftLeftFunction(size_t _numBits)
return createFunction(functionName, [&]() {
solAssert(_numBits < 256, "");
return
- Whiskers(R"(function <functionName>(value) -> newValue {
+ Whiskers(R"(
+ function <functionName>(value) -> newValue {
newValue := mul(value, <multiplier>)
- })")
+ }
+ )")
("functionName", functionName)
("multiplier", toCompactHexWithPrefix(u256(1) << _numBits))
.render();
@@ -1010,9 +1028,11 @@ string ABIFunctions::shiftRightFunction(size_t _numBits, bool _signed)
return createFunction(functionName, [&]() {
solAssert(_numBits < 256, "");
return
- Whiskers(R"(function <functionName>(value) -> newValue {
+ Whiskers(R"(
+ function <functionName>(value) -> newValue {
newValue := <div>(value, <multiplier>)
- })")
+ }
+ )")
("functionName", functionName)
("div", _signed ? "sdiv" : "div")
("multiplier", toCompactHexWithPrefix(u256(1) << _numBits))
@@ -1025,9 +1045,11 @@ string ABIFunctions::roundUpFunction()
string functionName = "round_up_to_mul_of_32";
return createFunction(functionName, [&]() {
return
- Whiskers(R"(function <functionName>(value) -> result {
+ Whiskers(R"(
+ function <functionName>(value) -> result {
result := and(add(value, 31), not(31))
- })")
+ }
+ )")
("functionName", functionName)
.render();
});
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 37aa1aea..f9b181ae 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -191,7 +191,7 @@ void CompilerUtils::encodeToMemory(
{
// Use the new JULIA-based encoding function
auto stackHeightBefore = m_context.stackHeight();
- abiEncode(_givenTypes, targetTypes, _encodeAsLibraryTypes);
+ abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes);
solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), "");
return;
}
@@ -302,7 +302,7 @@ void CompilerUtils::encodeToMemory(
popStackSlots(argSize + dynPointers + 1);
}
-void CompilerUtils::abiEncode(
+void CompilerUtils::abiEncodeV2(
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes
@@ -541,7 +541,7 @@ void CompilerUtils::convertType(
else
{
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
- IntegerType addressType(0, IntegerType::Modifier::Address);
+ IntegerType addressType(160, IntegerType::Modifier::Address);
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::RationalNumber)
@@ -596,7 +596,6 @@ void CompilerUtils::convertType(
storeInMemoryDynamic(IntegerType(256));
// stack: mempos datapos
storeStringData(data);
- break;
}
else
solAssert(
@@ -810,9 +809,8 @@ void CompilerUtils::convertType(
if (_cleanupNeeded)
m_context << Instruction::ISZERO << Instruction::ISZERO;
break;
- case Type::Category::Function:
- {
- if (targetTypeCategory == Type::Category::Integer)
+ default:
+ if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Integer)
{
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
solAssert(targetType.isAddress(), "Function type can only be converted to address.");
@@ -821,17 +819,16 @@ void CompilerUtils::convertType(
// stack: <address> <function_id>
m_context << Instruction::POP;
- break;
}
- }
- // fall-through
- default:
- // All other types should not be convertible to non-equal types.
- solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
- if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32)
+ else
+ {
+ // All other types should not be convertible to non-equal types.
+ solAssert(_typeOnStack == _targetType, "Invalid type conversion requested.");
+ if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32)
m_context
<< ((u256(1) << (8 * _targetType.storageBytes())) - 1)
<< Instruction::AND;
+ }
break;
}
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 5e45699b..ad3989ad 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -102,13 +102,26 @@ public:
/// @note the locations of target reference types are ignored, because it will always be
/// memory.
void encodeToMemory(
- TypePointers const& _givenTypes = {},
- TypePointers const& _targetTypes = {},
- bool _padToWords = true,
- bool _copyDynamicDataInPlace = false,
+ TypePointers const& _givenTypes,
+ TypePointers const& _targetTypes,
+ bool _padToWords,
+ bool _copyDynamicDataInPlace,
bool _encodeAsLibraryTypes = false
);
+ /// Special case of @a encodeToMemory which assumes tight packing, e.g. no zero padding
+ /// and dynamic data is encoded in-place.
+ /// Stack pre: <value0> <value1> ... <valueN-1> <head_start>
+ /// Stack post: <mem_ptr>
+ void packedEncode(
+ TypePointers const& _givenTypes,
+ TypePointers const& _targetTypes,
+ bool _encodeAsLibraryTypes = false
+ )
+ {
+ encodeToMemory(_givenTypes, _targetTypes, false, true, _encodeAsLibraryTypes);
+ }
+
/// Special case of @a encodeToMemory which assumes that everything is padded to words
/// and dynamic data is not copied in place (i.e. a proper ABI encoding).
/// Stack pre: <value0> <value1> ... <valueN-1> <head_start>
@@ -117,6 +130,20 @@ public:
TypePointers const& _givenTypes,
TypePointers const& _targetTypes,
bool _encodeAsLibraryTypes = false
+ )
+ {
+ encodeToMemory(_givenTypes, _targetTypes, true, false, _encodeAsLibraryTypes);
+ }
+
+ /// Special case of @a encodeToMemory which assumes that everything is padded to words
+ /// and dynamic data is not copied in place (i.e. a proper ABI encoding).
+ /// Uses a new, less tested encoder implementation.
+ /// Stack pre: <value0> <value1> ... <valueN-1> <head_start>
+ /// Stack post: <mem_ptr>
+ void abiEncodeV2(
+ TypePointers const& _givenTypes,
+ TypePointers const& _targetTypes,
+ bool _encodeAsLibraryTypes = false
);
/// Zero-initialises (the data part of) an already allocated memory array.
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 92782b8d..429db532 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -421,7 +421,7 @@ void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParamete
utils.fetchFreeMemoryPointer();
//@todo optimization: if we return a single memory array, there should be enough space before
// its data to add the needed parts and we avoid a memory copy.
- utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary);
+ utils.abiEncode(_typeParameters, _typeParameters, _isLibrary);
utils.toSizeAfterFreeMemoryPointer();
m_context << Instruction::RETURN;
}
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index c94baa10..c2bf0f5c 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -581,7 +581,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_context << Instruction::ADD;
}
);
- utils().encodeToMemory(argumentTypes, function.parameterTypes());
+ utils().abiEncode(argumentTypes, function.parameterTypes());
// now on stack: memory_end_ptr
// need: size, offset, endowment
utils().toSizeAfterFreeMemoryPointer();
@@ -675,7 +675,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
argumentTypes.push_back(arg->annotation().type);
}
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
+ solAssert(!function.padArguments(), "");
+ utils().packedEncode(argumentTypes, TypePointers());
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::KECCAK256;
break;
@@ -694,11 +695,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
arguments.front()->accept(*this);
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(
+ utils().packedEncode(
{arguments.front()->annotation().type},
- {function.parameterTypes().front()},
- false,
- true);
+ {function.parameterTypes().front()}
+ );
utils().toSizeAfterFreeMemoryPointer();
m_context << logInstruction(logNumber);
break;
@@ -717,11 +717,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (auto const& arrayType = dynamic_pointer_cast<ArrayType const>(function.parameterTypes()[arg - 1]))
{
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(
+ utils().packedEncode(
{arguments[arg - 1]->annotation().type},
- {arrayType},
- false,
- true
+ {arrayType}
);
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::KECCAK256;
@@ -751,7 +749,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
nonIndexedParamTypes.push_back(function.parameterTypes()[arg]);
}
utils().fetchFreeMemoryPointer();
- utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes);
+ utils().abiEncode(nonIndexedArgTypes, nonIndexedParamTypes);
// need: topic1 ... topicn memsize memstart
utils().toSizeAfterFreeMemoryPointer();
m_context << logInstruction(numIndexed);
@@ -1014,59 +1012,65 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
switch (_memberAccess.expression().annotation().type->category())
{
case Type::Category::Contract:
+ case Type::Category::Integer:
{
bool alsoSearchInteger = false;
- ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
- if (type.isSuper())
+ if (_memberAccess.expression().annotation().type->category() == Type::Category::Contract)
{
- solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
- utils().pushCombinedFunctionEntryLabel(m_context.superFunction(
- dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
- type.contractDefinition()
- ));
+ ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
+ if (type.isSuper())
+ {
+ solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
+ utils().pushCombinedFunctionEntryLabel(m_context.superFunction(
+ dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
+ type.contractDefinition()
+ ));
+ }
+ else
+ {
+ // ordinary contract type
+ if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
+ {
+ u256 identifier;
+ if (auto const* variable = dynamic_cast<VariableDeclaration const*>(declaration))
+ identifier = FunctionType(*variable).externalIdentifier();
+ else if (auto const* function = dynamic_cast<FunctionDefinition const*>(declaration))
+ identifier = FunctionType(*function).externalIdentifier();
+ else
+ solAssert(false, "Contract member is neither variable nor function.");
+ utils().convertType(type, IntegerType(160, IntegerType::Modifier::Address), true);
+ m_context << identifier;
+ }
+ else
+ // not found in contract, search in members inherited from address
+ alsoSearchInteger = true;
+ }
}
else
+ alsoSearchInteger = true;
+
+ if (alsoSearchInteger)
{
- // ordinary contract type
- if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
+ if (member == "balance")
{
- u256 identifier;
- if (auto const* variable = dynamic_cast<VariableDeclaration const*>(declaration))
- identifier = FunctionType(*variable).externalIdentifier();
- else if (auto const* function = dynamic_cast<FunctionDefinition const*>(declaration))
- identifier = FunctionType(*function).externalIdentifier();
- else
- solAssert(false, "Contract member is neither variable nor function.");
- utils().convertType(type, IntegerType(0, IntegerType::Modifier::Address), true);
- m_context << identifier;
+ utils().convertType(
+ *_memberAccess.expression().annotation().type,
+ IntegerType(160, IntegerType::Modifier::Address),
+ true
+ );
+ m_context << Instruction::BALANCE;
}
+ else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall"}).count(member))
+ utils().convertType(
+ *_memberAccess.expression().annotation().type,
+ IntegerType(160, IntegerType::Modifier::Address),
+ true
+ );
else
- // not found in contract, search in members inherited from address
- alsoSearchInteger = true;
+ solAssert(false, "Invalid member access to integer");
}
- if (!alsoSearchInteger)
- break;
- }
- // fall-through
- case Type::Category::Integer:
- if (member == "balance")
- {
- utils().convertType(
- *_memberAccess.expression().annotation().type,
- IntegerType(0, IntegerType::Modifier::Address),
- true
- );
- m_context << Instruction::BALANCE;
- }
- else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall"}).count(member))
- utils().convertType(
- *_memberAccess.expression().annotation().type,
- IntegerType(0, IntegerType::Modifier::Address),
- true
- );
- else
- solAssert(false, "Invalid member access to integer");
break;
+ }
case Type::Category::Function:
if (member == "selector")
{
@@ -1206,11 +1210,9 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
utils().fetchFreeMemoryPointer();
// stack: base index mem
// note: the following operations must not allocate memory!
- utils().encodeToMemory(
+ utils().packedEncode(
TypePointers{_indexAccess.indexExpression()->annotation().type},
- TypePointers{keyType},
- false,
- true
+ TypePointers{keyType}
);
m_context << Instruction::SWAP1;
utils().storeInMemoryDynamic(IntegerType(256));
diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp
index 522928f0..0ceed3a7 100644
--- a/libsolidity/formal/Z3Interface.cpp
+++ b/libsolidity/formal/Z3Interface.cpp
@@ -72,28 +72,21 @@ void Z3Interface::addAssertion(Expression const& _expr)
pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _expressionsToEvaluate)
{
-// cout << "---------------------------------" << endl;
-// cout << m_solver << endl;
CheckResult result;
switch (m_solver.check())
{
case z3::check_result::sat:
result = CheckResult::SATISFIABLE;
- cout << "sat" << endl;
break;
case z3::check_result::unsat:
result = CheckResult::UNSATISFIABLE;
- cout << "unsat" << endl;
break;
case z3::check_result::unknown:
result = CheckResult::UNKNOWN;
- cout << "unknown" << endl;
break;
default:
solAssert(false, "");
}
-// cout << "---------------------------------" << endl;
-
vector<string> values;
if (result != CheckResult::UNSATISFIABLE)
@@ -142,7 +135,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
return m_context.int_val(n.c_str());
}
- assert(arity.count(n) && arity.at(n) == arguments.size());
+ solAssert(arity.count(n) && arity.at(n) == arguments.size(), "");
if (n == "ite")
return z3::ite(arguments[0], arguments[1], arguments[2]);
else if (n == "not")
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index 3087ad86..1f4df75b 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -256,7 +256,7 @@ std::map<string, dev::solidity::Instruction> const& Parser::instructions()
{
if (
instruction.second == solidity::Instruction::JUMPDEST ||
- (solidity::Instruction::PUSH1 <= instruction.second && instruction.second <= solidity::Instruction::PUSH32)
+ solidity::isPushInstruction(instruction.second)
)
continue;
string name = instruction.first;
@@ -443,9 +443,9 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
ret.location = ret.instruction.location;
solidity::Instruction instr = ret.instruction.instruction;
InstructionInfo instrInfo = instructionInfo(instr);
- if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16)
+ if (solidity::isDupInstruction(instr))
fatalParserError("DUPi instructions not allowed for functional notation");
- if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16)
+ if (solidity::isSwapInstruction(instr))
fatalParserError("SWAPi instructions not allowed for functional notation");
expectToken(Token::LParen);
unsigned args = unsigned(instrInfo.args);
diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp
index 852b392c..22cc0266 100644
--- a/libsolidity/interface/GasEstimator.cpp
+++ b/libsolidity/interface/GasEstimator.cpp
@@ -48,7 +48,7 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio
ControlFlowGraph cfg(_items);
for (BasicBlock const& block: cfg.optimisedBlocks())
{
- assertThrow(!!block.startState, OptimizerException, "");
+ solAssert(!!block.startState, "");
GasMeter meter(block.startState->copy());
auto const end = _items.begin() + block.end;
for (auto iter = _items.begin() + block.begin; iter != end; ++iter)
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index 9a8bb358..821e81d2 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -1133,6 +1133,7 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme
options.allowVar = true;
options.allowLocationSpecifier = true;
variables.push_back(parseVariableDeclaration(options, _lookAheadArrayType));
+ nodeFactory.setEndPositionFromNode(variables.back());
}
if (m_scanner->currentToken() == Token::Assign)
{
diff --git a/lllc/main.cpp b/lllc/main.cpp
index 06a0fc81..912ce16a 100644
--- a/lllc/main.cpp
+++ b/lllc/main.cpp
@@ -138,7 +138,7 @@ int main(int argc, char** argv)
}
else if (mode == Binary || mode == Hex)
{
- auto bs = compileLLL(src, optimise ? true : false, &errors);
+ auto bs = compileLLL(src, optimise ? true : false, &errors, contentsString);
if (mode == Hex)
cout << toHex(bs) << endl;
else if (mode == Binary)
@@ -147,7 +147,7 @@ int main(int argc, char** argv)
else if (mode == ParseTree)
cout << parseLLL(src) << endl;
else if (mode == Assembly)
- cout << compileLLLToAsm(src, optimise ? true : false, &errors) << endl;
+ cout << compileLLLToAsm(src, optimise ? true : false, &errors, contentsString) << endl;
for (auto const& i: errors)
cerr << i << endl;
if ( errors.size() )
diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh
index 3a1abe10..01dee81d 100755
--- a/scripts/install_deps.sh
+++ b/scripts/install_deps.sh
@@ -256,15 +256,6 @@ case $(uname -s) in
#------------------------------------------------------------------------------
# Ubuntu
#
-# TODO - I wonder whether all of the Ubuntu-variants need some special
-# treatment?
-#
-# TODO - We should also test this code on Ubuntu Server, Ubuntu Snappy Core
-# and Ubuntu Phone.
-#
-# TODO - Our Ubuntu build is only working for amd64 and i386 processors.
-# It would be good to add armel, armhf and arm64.
-# See https://github.com/ethereum/webthree-umbrella/issues/228.
#------------------------------------------------------------------------------
Ubuntu)
@@ -320,6 +311,14 @@ case $(uname -s) in
libboost-all-dev \
"$install_z3"
if [ "$CI" = true ]; then
+ # install Z3 from PPA if the distribution does not provide it
+ if ! dpkg -l libz3-dev > /dev/null 2>&1
+ then
+ sudo apt-add-repository -y ppa:hvr/z3
+ sudo apt-get -y update
+ sudo apt-get -y install libz3-dev
+ fi
+
# Install 'eth', for use in the Solidity Tests-over-IPC.
# We will not use this 'eth', but its dependencies
sudo add-apt-repository -y ppa:ethereum/ethereum
diff --git a/scripts/tests.sh b/scripts/tests.sh
index 5d7eb0e1..bf3e3455 100755
--- a/scripts/tests.sh
+++ b/scripts/tests.sh
@@ -42,8 +42,8 @@ elif [ -z $CI ]; then
ETH_PATH="eth"
else
mkdir -p /tmp/test
- wget -O /tmp/test/eth https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/eth
- test "$(shasum /tmp/test/eth)" = "c132e8989229e4840831a4fb1a1d058b732a11d5 /tmp/test/eth"
+ wget -O /tmp/test/eth https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/eth_byzantium
+ test "$(shasum /tmp/test/eth)" = "6e16ae5e0a0079d85fd63fb43547be3c52410e7e /tmp/test/eth"
sync
chmod +x /tmp/test/eth
sync # Otherwise we might get a "text file busy" error
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index c4fbfefb..768c8c4b 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -217,11 +217,11 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
{
"sealEngine": "NoProof",
"params": {
- "accountStartNonce": "0x",
+ "accountStartNonce": "0x00",
"maximumExtraDataSize": "0x1000000",
"blockReward": "0x",
- "allowFutureBlocks": "1",
- "homsteadForkBlock": "0x00",
+ "allowFutureBlocks": true,
+ "homesteadForkBlock": "0x00",
"EIP150ForkBlock": "0x00",
"EIP158ForkBlock": "0x00"
},
diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp
index 094b59c6..c8747a06 100644
--- a/test/TestHelper.cpp
+++ b/test/TestHelper.cpp
@@ -45,6 +45,8 @@ Options::Options()
showMessages = true;
else if (string(suite.argv[i]) == "--no-ipc")
disableIPC = true;
+ else if (string(suite.argv[i]) == "--no-smt")
+ disableSMT = true;
if (!disableIPC && ipcPath.empty())
if (auto path = getenv("ETH_TEST_IPC"))
diff --git a/test/TestHelper.h b/test/TestHelper.h
index d50568ad..d25c5cd8 100644
--- a/test/TestHelper.h
+++ b/test/TestHelper.h
@@ -35,6 +35,7 @@ struct Options: boost::noncopyable
bool showMessages = false;
bool optimize = false;
bool disableIPC = false;
+ bool disableSMT = false;
static Options const& get();
diff --git a/test/boostTest.cpp b/test/boostTest.cpp
index d8c5b678..7b452e06 100644
--- a/test/boostTest.cpp
+++ b/test/boostTest.cpp
@@ -39,6 +39,17 @@
using namespace boost::unit_test;
+namespace
+{
+void removeTestSuite(std::string const& _name)
+{
+ master_test_suite_t& master = framework::master_test_suite();
+ auto id = master.get(_name);
+ assert(id != INV_TEST_UNIT_ID);
+ master.remove(id);
+}
+}
+
test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
{
master_test_suite_t& master = framework::master_test_suite();
@@ -57,12 +68,10 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
"SolidityEndToEndTest",
"SolidityOptimizer"
})
- {
- auto id = master.get(suite);
- assert(id != INV_TEST_UNIT_ID);
- master.remove(id);
- }
+ removeTestSuite(suite);
}
+ if (dev::test::Options::get().disableSMT)
+ removeTestSuite("SMTChecker");
return 0;
}
diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp
new file mode 100644
index 00000000..2d66bce1
--- /dev/null
+++ b/test/liblll/Compiler.cpp
@@ -0,0 +1,128 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Alex Beregszaszi
+ * @date 2017
+ * Unit tests for the LLL compiler.
+ */
+
+#include <string>
+#include <memory>
+#include <boost/test/unit_test.hpp>
+#include <liblll/Compiler.h>
+
+using namespace std;
+
+namespace dev
+{
+namespace lll
+{
+namespace test
+{
+
+namespace
+{
+
+bool successCompile(std::string const& _sourceCode)
+{
+ std::vector<std::string> errors;
+ bytes bytecode = eth::compileLLL(_sourceCode, false, &errors);
+ if (!errors.empty())
+ return false;
+ if (bytecode.empty())
+ return false;
+ return true;
+}
+
+}
+
+BOOST_AUTO_TEST_SUITE(LLLCompiler)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ char const* sourceCode = "1";
+ BOOST_CHECK(successCompile(sourceCode));
+}
+
+BOOST_AUTO_TEST_CASE(switch_valid)
+{
+ char const* sourceCode = R"(
+ (switch (origin))
+ )";
+ BOOST_CHECK(successCompile(sourceCode));
+ sourceCode = R"(
+ (switch
+ 1 (panic)
+ 2 (panic))
+ )";
+ BOOST_CHECK(successCompile(sourceCode));
+ sourceCode = R"(
+ (switch
+ 1 (panic)
+ 2 (panic)
+ (panic))
+ )";
+ BOOST_CHECK(successCompile(sourceCode));
+ sourceCode = R"(
+ (switch
+ 1 (origin)
+ 2 (origin)
+ (origin))
+ )";
+ BOOST_CHECK(successCompile(sourceCode));
+}
+
+BOOST_AUTO_TEST_CASE(switch_invalid_arg_count)
+{
+ char const* sourceCode = R"(
+ (switch)
+ )";
+ BOOST_CHECK(!successCompile(sourceCode));
+}
+
+BOOST_AUTO_TEST_CASE(switch_inconsistent_return_count)
+{
+ // cannot return stack items if the default case is not present
+ char const* sourceCode = R"(
+ (switch
+ 1 (origin)
+ 2 (origin)
+ )";
+ BOOST_CHECK(!successCompile(sourceCode));
+ // return count mismatch
+ sourceCode = R"(
+ (switch
+ 1 (origin)
+ 2 (origin)
+ (panic))
+ )";
+ BOOST_CHECK(!successCompile(sourceCode));
+ // return count mismatch
+ sourceCode = R"(
+ (switch
+ 1 (panic)
+ 2 (panic)
+ (origin))
+ )";
+ BOOST_CHECK(!successCompile(sourceCode));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+} // end namespaces
diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp
index 9292d963..1a5bb490 100644
--- a/test/liblll/EndToEndTest.cpp
+++ b/test/liblll/EndToEndTest.cpp
@@ -215,6 +215,92 @@ BOOST_AUTO_TEST_CASE(conditional_nested_then)
BOOST_CHECK(callContractFunction("test()", 0xfc) == encodeArgs(u256(6)));
}
+BOOST_AUTO_TEST_CASE(conditional_switch)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (def 'input (calldataload 0x04))
+ ;; Calculates width in bytes of utf-8 characters.
+ (return
+ (switch
+ (< input 0x80) 1
+ (< input 0xE0) 2
+ (< input 0xF0) 3
+ (< input 0xF8) 4
+ (< input 0xFC) 5
+ 6))))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()", 0x00) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("test()", 0x80) == encodeArgs(u256(2)));
+ BOOST_CHECK(callContractFunction("test()", 0xe0) == encodeArgs(u256(3)));
+ BOOST_CHECK(callContractFunction("test()", 0xf0) == encodeArgs(u256(4)));
+ BOOST_CHECK(callContractFunction("test()", 0xf8) == encodeArgs(u256(5)));
+ BOOST_CHECK(callContractFunction("test()", 0xfc) == encodeArgs(u256(6)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_switch_one_arg_with_deposit)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return
+ (switch 42)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_switch_one_arg_no_deposit)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (switch [0]:42)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callFallback() == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_switch_two_args)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (seq
+ (switch (= (calldataload 0x04) 1) [0]:42)
+ (return 0x00 0x20)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()", 0) == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("test()", 1) == encodeArgs(u256(42)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_switch_three_args_with_deposit)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (return
+ (switch (= (calldataload 0x04) 1) 41 42)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()", 0) == encodeArgs(u256(42)));
+ BOOST_CHECK(callContractFunction("test()", 1) == encodeArgs(u256(41)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_switch_three_args_no_deposit)
+{
+ char const* sourceCode = R"(
+ (returnlll
+ (switch
+ (= (calldataload 0x04) 1) (return 41)
+ (return 42)))
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("test()", 0) == encodeArgs(u256(42)));
+ BOOST_CHECK(callContractFunction("test()", 1) == encodeArgs(u256(41)));
+}
+
BOOST_AUTO_TEST_CASE(exp_operator_const)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index 5f5f6411..3bdc40a0 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -25,6 +25,8 @@
#include <libsolidity/ast/AST.h>
+#include <libsolidity/parsing/Scanner.h>
+
#include <libdevcore/SHA3.h>
#include <boost/test/unit_test.hpp>
@@ -46,8 +48,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
m_compiler.addSource("", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source);
if (!m_compiler.parse())
{
- printErrors();
- BOOST_ERROR("Parsing contract failed in analysis test suite.");
+ BOOST_ERROR("Parsing contract failed in analysis test suite:" + formatErrors());
}
m_compiler.analyze();
@@ -56,15 +57,24 @@ AnalysisFramework::parseAnalyseAndReturnError(
for (auto const& currentError: m_compiler.errors())
{
solAssert(currentError->comment(), "");
- if (currentError->comment()->find("This is a pre-release compiler version") == 0)
- continue;
+ if (currentError->type() == Error::Type::Warning)
+ {
+ bool ignoreWarning = false;
+ for (auto const& filter: m_warningsToFilter)
+ if (currentError->comment()->find(filter) == 0)
+ {
+ ignoreWarning = true;
+ break;
+ }
+ if (ignoreWarning)
+ continue;
+ }
if (_reportWarnings || (currentError->type() != Error::Type::Warning))
{
if (firstError && !_allowMultipleErrors)
{
- printErrors();
- BOOST_FAIL("Multiple errors found.");
+ BOOST_FAIL("Multiple errors found: " + formatErrors());
}
if (!firstError)
firstError = currentError;
@@ -78,7 +88,10 @@ SourceUnit const* AnalysisFramework::parseAndAnalyse(string const& _source)
{
auto sourceAndError = parseAnalyseAndReturnError(_source);
BOOST_REQUIRE(!!sourceAndError.first);
- BOOST_REQUIRE(!sourceAndError.second);
+ string message;
+ if (sourceAndError.second)
+ message = "Unexpected error: " + formatError(*sourceAndError.second);
+ BOOST_REQUIRE_MESSAGE(!sourceAndError.second, message);
return sourceAndError.first;
}
@@ -91,17 +104,23 @@ Error AnalysisFramework::expectError(std::string const& _source, bool _warning,
{
auto sourceAndError = parseAnalyseAndReturnError(_source, _warning, true, _allowMultiple);
BOOST_REQUIRE(!!sourceAndError.second);
- BOOST_REQUIRE(!!sourceAndError.first);
+ BOOST_REQUIRE_MESSAGE(!!sourceAndError.first, "Expected error, but no error happened.");
return *sourceAndError.second;
}
-void AnalysisFramework::printErrors()
+string AnalysisFramework::formatErrors()
{
+ string message;
for (auto const& error: m_compiler.errors())
- SourceReferenceFormatter::printExceptionInformation(
- std::cerr,
- *error,
- (error->type() == Error::Type::Warning) ? "Warning" : "Error",
+ message += formatError(*error);
+ return message;
+}
+
+string AnalysisFramework::formatError(Error const& _error)
+{
+ return SourceReferenceFormatter::formatExceptionInformation(
+ _error,
+ (_error.type() == Error::Type::Warning) ? "Warning" : "Error",
[&](std::string const& _sourceName) -> solidity::Scanner const& { return m_compiler.scanner(_sourceName); }
);
}
diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h
index 172ae01b..a566ba1d 100644
--- a/test/libsolidity/AnalysisFramework.h
+++ b/test/libsolidity/AnalysisFramework.h
@@ -45,7 +45,7 @@ class AnalysisFramework
{
protected:
- std::pair<SourceUnit const*, std::shared_ptr<Error const>>
+ virtual std::pair<SourceUnit const*, std::shared_ptr<Error const>>
parseAnalyseAndReturnError(
std::string const& _source,
bool _reportWarnings = false,
@@ -57,7 +57,8 @@ protected:
bool success(std::string const& _source);
Error expectError(std::string const& _source, bool _warning = false, bool _allowMultiple = false);
- void printErrors();
+ std::string formatErrors();
+ std::string formatError(Error const& _error);
static ContractDefinition const* retrieveContractByName(SourceUnit const& _source, std::string const& _name);
static FunctionTypePointer retrieveFunctionBySignature(
@@ -65,6 +66,7 @@ protected:
std::string const& _signature
);
+ std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"};
dev::solidity::CompilerStack m_compiler;
};
@@ -104,7 +106,10 @@ CHECK_ERROR_OR_WARNING(text, Warning, substring, true, true)
do \
{ \
auto sourceAndError = parseAnalyseAndReturnError((text), true); \
- BOOST_CHECK(sourceAndError.second == nullptr); \
+ std::string message; \
+ if (sourceAndError.second) \
+ message = formatError(*sourceAndError.second); \
+ BOOST_CHECK_MESSAGE(!sourceAndError.second, message); \
} \
while(0)
diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp
index b759678f..c2886f5b 100644
--- a/test/libsolidity/GasMeter.cpp
+++ b/test/libsolidity/GasMeter.cpp
@@ -21,7 +21,6 @@
*/
#include <test/libsolidity/SolidityExecutionFramework.h>
-#include <libevmasm/EVMSchedule.h>
#include <libevmasm/GasMeter.h>
#include <libevmasm/KnownState.h>
#include <libevmasm/PathGasMeter.h>
@@ -63,15 +62,13 @@ public:
void testCreationTimeGas(string const& _sourceCode)
{
- EVMSchedule schedule;
-
compileAndRun(_sourceCode);
auto state = make_shared<KnownState>();
PathGasMeter meter(*m_compiler.assemblyItems());
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
// costs for deployment
- gas += bytecodeSize * schedule.createDataGas;
+ gas += bytecodeSize * GasCosts::createDataGas;
// costs for transaction
gas += gasForTransaction(m_compiler.object().bytecode, true);
@@ -103,10 +100,9 @@ public:
static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
{
- EVMSchedule schedule;
- GasMeter::GasConsumption gas = _isCreation ? schedule.txCreateGas : schedule.txGas;
+ GasMeter::GasConsumption gas = _isCreation ? GasCosts::txCreateGas : GasCosts::txGas;
for (auto i: _data)
- gas += i != 0 ? schedule.txDataNonZeroGas : schedule.txDataZeroGas;
+ gas += i != 0 ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas;
return gas;
}
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
new file mode 100644
index 00000000..d58f296f
--- /dev/null
+++ b/test/libsolidity/SMTChecker.cpp
@@ -0,0 +1,86 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Unit tests for the SMT checker.
+ */
+
+#include <test/libsolidity/AnalysisFramework.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+class SMTCheckerFramework: public AnalysisFramework
+{
+public:
+ SMTCheckerFramework()
+ {
+ m_warningsToFilter.push_back("Experimental features are turned on.");
+ }
+
+protected:
+ virtual std::pair<SourceUnit const*, std::shared_ptr<Error const>>
+ parseAnalyseAndReturnError(
+ std::string const& _source,
+ bool _reportWarnings = false,
+ bool _insertVersionPragma = true,
+ bool _allowMultipleErrors = false
+ )
+ {
+ return AnalysisFramework::parseAnalyseAndReturnError(
+ "pragma experimental SMTChecker;\n" + _source,
+ _reportWarnings,
+ _insertVersionPragma,
+ _allowMultipleErrors
+ );
+ }
+};
+
+BOOST_FIXTURE_TEST_SUITE(SMTChecker, SMTCheckerFramework)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ string text = R"(
+ contract C { }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(simple_overflow)
+{
+ string text = R"(
+ contract C {
+ function f(uint a, uint b) public pure returns (uint) { return a + b; }
+ }
+ )";
+ CHECK_WARNING(text, "Overflow (resulting value larger than");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 82dedf85..35916ec7 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1457,7 +1457,7 @@ BOOST_AUTO_TEST_CASE(msg_sig)
}
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("foo(uint256)"), encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes())));
+ ABI_CHECK(callContractFunction("foo(uint256)", 0), encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes())));
}
BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same)
@@ -1473,7 +1473,7 @@ BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same)
}
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("foo(uint256)"), encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes())));
+ ABI_CHECK(callContractFunction("foo(uint256)", 0), encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes())));
}
BOOST_AUTO_TEST_CASE(now)
@@ -1494,7 +1494,7 @@ BOOST_AUTO_TEST_CASE(now)
size_t endTime = blockTimestamp(endBlock);
BOOST_CHECK(startBlock != endBlock);
BOOST_CHECK(startTime != endTime);
- BOOST_CHECK(ret == encodeArgs(true, endTime));
+ ABI_CHECK(ret, encodeArgs(true, endTime));
}
BOOST_AUTO_TEST_CASE(type_conversions_cleanup)
@@ -3090,7 +3090,7 @@ BOOST_AUTO_TEST_CASE(event_anonymous_with_topics)
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous;
- function deposit(bytes32 _id, bool _manually) payable {
+ function deposit(bytes32 _id) payable {
Deposit(msg.sender, _id, msg.value, 2, "abc");
}
}
@@ -3098,7 +3098,7 @@ BOOST_AUTO_TEST_CASE(event_anonymous_with_topics)
compileAndRun(sourceCode);
u256 value(18);
u256 id(0x1234);
- callContractFunctionWithValue("deposit(bytes32,bool)", value, id);
+ callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs("abc"));
@@ -3757,11 +3757,11 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
compileAndRun(sourceCode);
string data = "123456789012345678901234567890123";
BOOST_CHECK(storageEmpty(m_contractAddress));
- ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data), encodeArgs(true));
+ ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("copy()"), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
- ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data), encodeArgs(true));
+ ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress));
ABI_CHECK(callContractFunction("del()"), encodeArgs(true));
BOOST_CHECK(storageEmpty(m_contractAddress));
@@ -5185,7 +5185,7 @@ BOOST_AUTO_TEST_CASE(packed_storage_signed)
}
)";
compileAndRun(sourceCode);
- BOOST_CHECK( callContractFunction("test()") == encodeArgs(u256(-2), u256(4), u256(-112), u256(0)));
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(-2), u256(4), u256(-112), u256(0)));
}
BOOST_AUTO_TEST_CASE(external_types_in_calls)
@@ -5540,7 +5540,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
}
}
)";
- BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A").empty());
+ ABI_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A"), encodeArgs());
}
BOOST_AUTO_TEST_CASE(positive_integers_to_signed)
@@ -6505,31 +6505,32 @@ BOOST_AUTO_TEST_CASE(string_as_mapping_key)
"1"
};
for (unsigned i = 0; i < strings.size(); i++)
- BOOST_CHECK(callContractFunction(
+ ABI_CHECK(callContractFunction(
"set(string,uint256)",
u256(0x40),
u256(7 + i),
u256(strings[i].size()),
strings[i]
- ) == encodeArgs());
+ ), encodeArgs());
for (unsigned i = 0; i < strings.size(); i++)
- BOOST_CHECK(callContractFunction(
+ ABI_CHECK(callContractFunction(
"get(string)",
u256(0x20),
u256(strings[i].size()),
strings[i]
- ) == encodeArgs(u256(7 + i)));
+ ), encodeArgs(u256(7 + i)));
}
BOOST_AUTO_TEST_CASE(accessor_for_state_variable)
{
char const* sourceCode = R"(
- contract Lotto{
+ contract Lotto {
uint public ticketPrice = 500;
- })";
+ }
+ )";
- compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(500)));
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(500)));
}
BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable)
@@ -6537,10 +6538,11 @@ BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable)
char const* sourceCode = R"(
contract Lotto{
uint constant public ticketPrice = 555;
- })";
+ }
+ )";
- compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(555)));
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(555)));
}
BOOST_AUTO_TEST_CASE(state_variable_under_contract_name)
@@ -7402,7 +7404,7 @@ BOOST_AUTO_TEST_CASE(string_allocation_bug)
}
)";
compileAndRun(sourceCode);
- ABI_CHECK(callContractFunction("p(uint256)"), encodeArgs(
+ ABI_CHECK(callContractFunction("p(uint256)", 0), encodeArgs(
u256(0xbbbb),
u256(0xcccc),
u256(0x80),
@@ -7913,7 +7915,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_function_call_assignment)
}
)";
compileAndRun(sourceCode, 0, "C");
- BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7)));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7)));
}
BOOST_AUTO_TEST_CASE(inline_assembly_function_call2)
@@ -8776,8 +8778,8 @@ BOOST_AUTO_TEST_CASE(return_external_function_type)
)";
compileAndRun(sourceCode, 0, "C");
- BOOST_CHECK(
- callContractFunction("f()") ==
+ ABI_CHECK(
+ callContractFunction("f()"),
m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0)
);
}
@@ -10120,9 +10122,9 @@ BOOST_AUTO_TEST_CASE(function_types_sig)
}
)";
compileAndRun(sourceCode, 0, "C");
- BOOST_CHECK(callContractFunction("f()") == encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
- BOOST_CHECK(callContractFunction("g()") == encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
- BOOST_CHECK(callContractFunction("h()") == encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
+ ABI_CHECK(callContractFunction("h()"), encodeArgs(asString(FixedHash<4>(dev::keccak256("f()")).asBytes())));
}
BOOST_AUTO_TEST_CASE(constant_string)
@@ -10144,9 +10146,34 @@ BOOST_AUTO_TEST_CASE(constant_string)
}
)";
compileAndRun(sourceCode, 0, "C");
- BOOST_CHECK(callContractFunction("f()") == encodeDyn(string("\x03\x01\x02")));
- BOOST_CHECK(callContractFunction("g()") == encodeDyn(string("\x03\x01\x02")));
- BOOST_CHECK(callContractFunction("h()") == encodeDyn(string("hello")));
+ ABI_CHECK(callContractFunction("f()"), encodeDyn(string("\x03\x01\x02")));
+ ABI_CHECK(callContractFunction("g()"), encodeDyn(string("\x03\x01\x02")));
+ ABI_CHECK(callContractFunction("h()"), encodeDyn(string("hello")));
+}
+
+BOOST_AUTO_TEST_CASE(address_overload_resolution)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function balance() returns (uint) {
+ return 1;
+ }
+ function transfer(uint amount) returns (uint) {
+ return amount;
+ }
+ }
+ contract D {
+ function f() returns (uint) {
+ return (new C()).balance();
+ }
+ function g() returns (uint) {
+ return (new C()).transfer(5);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "D");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(5)));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 39c47f9c..ed223678 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -1395,6 +1395,61 @@ BOOST_AUTO_TEST_CASE(events_with_same_name)
BOOST_CHECK(success(text));
}
+BOOST_AUTO_TEST_CASE(events_with_same_name_unnamed_arguments)
+{
+ char const* text = R"(
+ contract test {
+ event A(uint);
+ event A(uint, uint);
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(events_with_same_name_different_types)
+{
+ char const* text = R"(
+ contract test {
+ event A(uint);
+ event A(bytes);
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(double_event_declaration)
+{
+ char const* text = R"(
+ contract test {
+ event A(uint i);
+ event A(uint i);
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Event with same name and arguments defined twice.");
+}
+
+BOOST_AUTO_TEST_CASE(double_event_declaration_ignores_anonymous)
+{
+ char const* text = R"(
+ contract test {
+ event A(uint i);
+ event A(uint i) anonymous;
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Event with same name and arguments defined twice.");
+}
+
+BOOST_AUTO_TEST_CASE(double_event_declaration_ignores_indexed)
+{
+ char const* text = R"(
+ contract test {
+ event A(uint i);
+ event A(uint indexed i);
+ }
+ )";
+ CHECK_ERROR(text, DeclarationError, "Event with same name and arguments defined twice.");
+}
+
BOOST_AUTO_TEST_CASE(event_call)
{
char const* text = R"(
@@ -2306,17 +2361,28 @@ BOOST_AUTO_TEST_CASE(assigning_value_to_const_variable)
CHECK_ERROR(text, TypeError, "Cannot assign to a constant variable.");
}
-BOOST_AUTO_TEST_CASE(assigning_state_to_const_variable)
+BOOST_AUTO_TEST_CASE(assigning_state_to_const_variable_0_4_x)
{
char const* text = R"(
contract C {
address constant x = msg.sender;
}
)";
- // Change to TypeError for 0.5.0.
CHECK_WARNING(text, "Initial value for constant variable has to be compile-time constant.");
}
+BOOST_AUTO_TEST_CASE(assigning_state_to_const_variable)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+
+ contract C {
+ address constant x = msg.sender;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Initial value for constant variable has to be compile-time constant.");
+}
+
BOOST_AUTO_TEST_CASE(constant_string_literal_disallows_assignment)
{
char const* text = R"(
@@ -2333,7 +2399,7 @@ BOOST_AUTO_TEST_CASE(constant_string_literal_disallows_assignment)
CHECK_ERROR(text, TypeError, "Index access for string is not possible.");
}
-BOOST_AUTO_TEST_CASE(assign_constant_function_value_to_constant)
+BOOST_AUTO_TEST_CASE(assign_constant_function_value_to_constant_0_4_x)
{
char const* text = R"(
contract C {
@@ -2341,10 +2407,22 @@ BOOST_AUTO_TEST_CASE(assign_constant_function_value_to_constant)
uint constant y = x();
}
)";
- // Change to TypeError for 0.5.0.
CHECK_WARNING(text, "Initial value for constant variable has to be compile-time constant.");
}
+BOOST_AUTO_TEST_CASE(assign_constant_function_value_to_constant)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+
+ contract C {
+ function () constant returns (uint) x;
+ uint constant y = x();
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Initial value for constant variable has to be compile-time constant.");
+}
+
BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_conversion)
{
char const* text = R"(
@@ -4135,6 +4213,8 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation)
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
+
+ // Test deprecation warning under < 0.5.0
text = R"(
contract test {
function f() pure public {
@@ -4154,6 +4234,29 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation)
}
)";
CHECK_WARNING(text,"Use of unary + is deprecated");
+
+ // Test syntax error under 0.5.0
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ ufixed16x2 a = +3.25;
+ fixed16x2 b = -3.25;
+ a; b;
+ }
+ }
+ )";
+ CHECK_ERROR(text, SyntaxError, "Use of unary + is deprecated");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f(uint x) pure public {
+ uint y = +x;
+ y;
+ }
+ }
+ )";
+ CHECK_ERROR(text, SyntaxError, "Use of unary + is deprecated");
}
BOOST_AUTO_TEST_CASE(leading_zero_rationals_convert)
@@ -4251,7 +4354,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_rational)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal");
+ CHECK_ERROR(text, TypeError, "Array with fractional length specified.");
}
BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type)
@@ -4263,7 +4366,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_signed_fixed_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
}
BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
@@ -4275,7 +4378,7 @@ BOOST_AUTO_TEST_CASE(invalid_array_declaration_with_unsigned_fixed_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal");
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
}
BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion)
@@ -6953,6 +7056,39 @@ BOOST_AUTO_TEST_CASE(warn_about_suicide)
CHECK_WARNING(text, "\"suicide\" has been deprecated in favour of \"selfdestruct\"");
}
+BOOST_AUTO_TEST_CASE(address_overload_resolution)
+{
+ char const* text = R"(
+ contract C {
+ function balance() returns (uint) {
+ this.balance; // to avoid pureness warning
+ return 1;
+ }
+ function transfer(uint amount) {
+ address(this).transfer(amount); // to avoid pureness warning
+ }
+ }
+ contract D {
+ function f() {
+ var x = (new C()).balance();
+ x;
+ (new C()).transfer(5);
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
+BOOST_AUTO_TEST_CASE(array_length_validation)
+{
+ char const* text = R"(
+ contract C {
+ uint[8**90] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}