aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml6
-rw-r--r--docs/control-structures.rst2
-rw-r--r--docs/types.rst37
-rw-r--r--docs/units-and-global-variables.rst98
-rw-r--r--libjulia/backends/evm/AbstractAssembly.h2
-rw-r--r--libsolidity/analysis/SemVerHandler.cpp39
-rw-r--r--libsolidity/analysis/TypeChecker.cpp4
-rw-r--r--libsolidity/ast/Types.cpp9
-rw-r--r--libsolidity/interface/StandardCompiler.cpp12
-rwxr-xr-xscripts/check_style.sh32
-rwxr-xr-xscripts/detect_trailing_whitespace.sh15
-rw-r--r--test/libsolidity/StandardCompiler.cpp2
-rw-r--r--test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol5
-rw-r--r--test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol5
18 files changed, 204 insertions, 94 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3e3d8c0a..8766883d 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -179,14 +179,14 @@ jobs:
name: Check spelling
command: ~/.local/bin/codespell -S "*.enc,.git" -I ./scripts/codespell_whitelist.txt
- test_trailing_whitespace:
+ test_check_style:
docker:
- image: buildpack-deps:artful
steps:
- checkout
- run:
name: Check for trailing whitespace
- command: ./scripts/detect_trailing_whitespace.sh
+ command: ./scripts/check_style.sh
test_buglist:
docker:
@@ -278,7 +278,7 @@ workflows:
build_all:
jobs:
- test_check_spelling: *build_on_tags
- - test_trailing_whitespace: *build_on_tags
+ - test_check_style: *build_on_tags
- test_buglist: *build_on_tags
- build_emscripten: *build_on_tags
- test_emscripten_solcjs:
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 745a0599..7c91cab7 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -385,6 +385,8 @@ In any case, you will get a warning about the outer variable being shadowed.
.. index:: ! exception, ! throw, ! assert, ! require, ! revert
+.. _assert-and-require:
+
Error handling: Assert, Require, Revert and Exceptions
======================================================
diff --git a/docs/types.rst b/docs/types.rst
index 49a0506a..ca1bd586 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -648,21 +648,27 @@ Another example that uses external function types::
.. index:: ! type;reference, ! reference type, storage, memory, location, array, struct
Reference Types
-==================
+===============
-Complex types, i.e. types which do not always fit into 256 bits have to be handled
-more carefully than the value-types we have already seen. Since copying
-them can be quite expensive, we have to think about whether we want them to be
-stored in **memory** (which is not persisting) or **storage** (where the state
-variables are held).
+Values of reference type can be modified through multiple different names.
+Contrast this with value types where you get an independent copy whenever
+a variable of value type is used. Because of that, reference types have to be handled
+more carefully than value types. Currently, reference types comprise structs,
+arrays and mappings. If you use a reference type, you always have to explicitly
+provide the data area where the type is stored: ``memory`` (whose lifetime is limited
+to a function call), ``storage`` (the location where the state variables are stored)
+or ``calldata`` (special data location that contains the function arguments,
+only available for external function call parameters).
+
+An assignment or type conversion that changes the data location will always incur an automatic copy operation,
+while assignments inside the same data location only copy in some cases for storage types.
.. _data-location:
Data location
-------------
-
-Every complex type, i.e. *arrays* and *structs*, has an additional
+Every reference type, i.e. *arrays* and *structs*, has an additional
annotation, the "data location", about where it is stored. There are three data locations:
``memory``, ``storage`` and ``calldata``. Calldata is only valid for parameters of external contract
functions and is required for this type of parameter. Calldata is a non-modifiable,
@@ -1059,11 +1065,13 @@ If ``a`` is an LValue (i.e. a variable or something that can be assigned to), th
delete
------
-``delete a`` assigns the initial value for the type to ``a``. I.e. for integers it is equivalent to ``a = 0``, but it can also be used on arrays, where it assigns a dynamic array of length zero or a static array of the same length with all elements reset. For structs, it assigns a struct with all members reset.
+``delete a`` assigns the initial value for the type to ``a``. I.e. for integers it is equivalent to ``a = 0``, but it can also be used on arrays, where it assigns a dynamic array of length zero or a static array of the same length with all elements reset. For structs, it assigns a struct with all members reset. In other words, the value of ``a`` after ``delete a`` is the same as if ``a`` would be declared without assignment, with the following caveat:
-``delete`` has no effect on whole mappings (as the keys of mappings may be arbitrary and are generally unknown). So if you delete a struct, it will reset all members that are not mappings and also recurse into the members unless they are mappings. However, individual keys and what they map to can be deleted.
+``delete`` has no effect on mappings (as the keys of mappings may be arbitrary and are generally unknown). So if you delete a struct, it will reset all members that are not mappings and also recurse into the members unless they are mappings. However, individual keys and what they map to can be deleted: If ``a`` is a mapping, then ``delete a[x]`` will delete the value stored at ``x``.
It is important to note that ``delete a`` really behaves like an assignment to ``a``, i.e. it stores a new object in ``a``.
+This distinction is visible when ``a`` is reference variable: It will only reset ``a`` itself, not the
+value it referred to previously.
::
@@ -1076,7 +1084,7 @@ It is important to note that ``delete a`` really behaves like an assignment to `
function f() public {
uint x = data;
delete x; // sets x to 0, does not affect data
- delete data; // sets data to 0, does not affect x which still holds a copy
+ delete data; // sets data to 0, does not affect x
uint[] storage y = dataArray;
delete dataArray; // this sets dataArray.length to zero, but as uint[] is a complex object, also
// y is affected which is an alias to the storage object
@@ -1105,12 +1113,15 @@ makes sense semantically and no information is lost: ``uint8`` is convertible to
(because ``uint256`` cannot hold e.g. ``-1``).
Any integer type that can be converted to ``uint160`` can also be converted to ``address``.
+For more details, please consult the sections about the types themselves.
+
Explicit Conversions
--------------------
If the compiler does not allow implicit conversion but you know what you are
doing, an explicit type conversion is sometimes possible. Note that this may
-give you some unexpected behaviour so be sure to test to ensure that the
+give you some unexpected behaviour and allows you to bypass some security
+features of the compiler, so be sure to test that the
result is what you want! Take the following example where you are converting
a negative ``int8`` to a ``uint``:
@@ -1209,3 +1220,5 @@ Addresses
As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum
test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type.
+
+Explicit conversions from ``bytes20`` or any integer type to ``address`` results in ``address payable``. \ No newline at end of file
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index d6ef393e..7f62e71e 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -7,15 +7,25 @@ Units and Globally Available Variables
Ether Units
===========
-A literal number can take a suffix of ``wei``, ``finney``, ``szabo`` or ``ether`` to convert between the subdenominations of Ether, where Ether currency numbers without a postfix are assumed to be Wei, e.g. ``2 ether == 2000 finney`` evaluates to ``true``.
+A literal number can take a suffix of ``wei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
+
+::
+
+ assert(1 wei == 1);
+ assert(1 szabo == 1e12);
+ assert(1 finney == 1e15);
+ assert(1 ether == 1e18);
+
+The only effect of the subdenomination suffix is a multiplication by a power of ten.
+
.. index:: time, seconds, minutes, hours, days, weeks, years
Time Units
==========
-Suffixes like ``seconds``, ``minutes``, ``hours``, ``days``, ``weeks`` and
-``years`` after literal numbers can be used to convert between units of time where seconds are the base
+Suffixes like ``seconds``, ``minutes``, ``hours``, ``days`` and ``weeks``
+after literal numbers can be used to specify units of time where seconds are the base
unit and units are considered naively in the following way:
* ``1 == 1 seconds``
@@ -23,7 +33,6 @@ unit and units are considered naively in the following way:
* ``1 hours == 60 minutes``
* ``1 days == 24 hours``
* ``1 weeks == 7 days``
- * ``1 years == 365 days``
Take care if you perform calendar calculations using these units, because
not every year equals 365 days and not even every day has 24 hours
@@ -32,7 +41,7 @@ Due to the fact that leap seconds cannot be predicted, an exact calendar
library has to be updated by an external oracle.
.. note::
- The suffix ``years`` has been deprecated due to the reasons above and cannot be used starting version 0.5.0.
+ The suffix ``years`` has been removed in version 0.5.0 due to the reasons above.
These suffixes cannot be applied to variables. If you want to
interpret some input variable in e.g. days, you can do it in the following way::
@@ -56,15 +65,14 @@ or are general-use utility functions.
Block and Transaction Properties
--------------------------------
-- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``.
+- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks
- ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
- ``block.gaslimit`` (``uint``): current block gaslimit
- ``block.number`` (``uint``): current block number
- ``block.timestamp`` (``uint``): current block timestamp as seconds since unix epoch
- ``gasleft() returns (uint256)``: remaining gas
-- ``msg.data`` (``bytes``): complete calldata
-- ``msg.gas`` (``uint``): remaining gas - deprecated in version 0.4.21 and to be replaced by ``gasleft()``
+- ``msg.data`` (``bytes calldata``): complete calldata
- ``msg.sender`` (``address payable``): sender of the message (current call)
- ``msg.sig`` (``bytes4``): first four bytes of the calldata (i.e. function identifier)
- ``msg.value`` (``uint``): number of wei sent with the message
@@ -94,20 +102,28 @@ Block and Transaction Properties
You can only access the hashes of the most recent 256 blocks, all other
values will be zero.
+.. note::
+ The function ``blockhash`` was previously known as ``block.blockhash``. It was deprecated in
+ version 0.4.22 and removed in version 0.5.0.
+
+.. note::
+ The function ``gasleft`` was previously known as ``msg.gas``. It was deprecated in
+ version 0.4.21 and removed in version 0.5.0.
+
.. index:: abi, encoding, packed
ABI Encoding and Decoding Functions
-----------------------------------
-- ``abi.decode(bytes encodedData, (...)) returns (...)``: ABI-decodes the given data, while the types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))``
-- ``abi.encode(...) returns (bytes)``: ABI-encodes the given arguments
-- ``abi.encodePacked(...) returns (bytes)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments
-- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector
-- ``abi.encodeWithSignature(string signature, ...) returns (bytes)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)```
+- ``abi.decode(bytes memory encodedData, (...)) returns (...)``: ABI-decodes the given data, while the types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))``
+- ``abi.encode(...) returns (bytes memory)``: ABI-encodes the given arguments
+- ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments
+- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector
+- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)```
.. note::
- These encoding functions can be used to craft data for function calls without actually
- calling a function. Furthermore, ``keccak256(abi.encodePacked(a, b))`` is a way
+ These encoding functions can be used to craft data for external function calls without actually
+ calling an external function. Furthermore, ``keccak256(abi.encodePacked(a, b))`` is a way
to compute the hash of structured data (although be aware that it is possible to
craft a "hash collision" using different inputs types).
@@ -119,15 +135,18 @@ See the documentation about the :ref:`ABI <ABI>` and the
Error Handling
--------------
+See the dedicated section on :ref:`assert and require<assert-and-require>` for
+more details on error handling and when to use which function.
+
``assert(bool condition)``:
- invalidates the transaction if the condition is not met - to be used for internal errors.
+ causes an invalid opcode and thus state change reversion if the condition is not met - to be used for internal errors.
``require(bool condition)``:
reverts if the condition is not met - to be used for errors in inputs or external components.
-``require(bool condition, string message)``:
+``require(bool condition, string memory message)``:
reverts if the condition is not met - to be used for errors in inputs or external components. Also provides an error message.
``revert()``:
abort execution and revert state changes
-``revert(string reason)``:
+``revert(string memory reason)``:
abort execution and revert state changes, providing an explanatory string
.. index:: keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography,
@@ -140,11 +159,9 @@ 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``. Assert that ``k != 0`` starting from version 0.5.0.
``keccak256(bytes memory) returns (bytes32)``:
- compute the Ethereum-SHA-3 (Keccak-256) hash of the input
+ compute the Keccak-256 hash of the input
``sha256(bytes memory) returns (bytes32)``:
compute the SHA-256 hash of the input
-``sha3(bytes memory) returns (bytes32)``:
- alias to ``keccak256``
``ripemd160(bytes memory) returns (bytes20)``:
compute RIPEMD-160 hash of the input
``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``:
@@ -158,26 +175,27 @@ Mathematical and Cryptographic Functions
It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net.
+.. note::
+ There used to be an alias for ``keccak256`` called ``sha3``, which was removed in version 0.5.0.
+
.. index:: balance, send, transfer, call, callcode, delegatecall, staticcall
.. _address_related:
-Address Related
----------------
+Members of Address Types
+------------------------
``<address>.balance`` (``uint256``):
balance of the :ref:`address` in Wei
``<address payable>.transfer(uint256 amount)``:
- send given amount of Wei to :ref:`address`, throws on failure, forwards 2300 gas stipend, not adjustable
+ send given amount of Wei to :ref:`address`, reverts on failure, forwards 2300 gas stipend, not adjustable
``<address payable>.send(uint256 amount) returns (bool)``:
send given amount of Wei to :ref:`address`, returns ``false`` on failure, forwards 2300 gas stipend, not adjustable
-``<address>.call(bytes memory) returns (bool)``:
- issue low-level ``CALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable
-``<address>.callcode(bytes memory) returns (bool)``:
- issue low-level ``CALLCODE`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable
-``<address>.delegatecall(bytes memory) returns (bool)``:
- issue low-level ``DELEGATECALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable
-``<address>.staticcall(bytes memory) returns (bool)``:
- issue low-level ``STATICCALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable
+``<address>.call(bytes memory) returns (bool, bytes memory)``:
+ issue low-level ``CALL`` with the given payload, returns success condition and return data, forwards all available gas, adjustable
+``<address>.delegatecall(bytes memory) returns (bool, bytes memory)``:
+ issue low-level ``DELEGATECALL`` with the given payload, returns success condition and return data, forwards all available gas, adjustable
+``<address>.staticcall(bytes memory) returns (bool, bytes memory)``:
+ issue low-level ``STATICCALL`` with the given payload, returns success condition and return data, forwards all available gas, adjustable
For more information, see the section on :ref:`address`.
@@ -192,14 +210,19 @@ For more information, see the section on :ref:`address`.
This is now forbidden and an explicit conversion to address must be done: ``address(this).balance``.
.. note::
- If storage variables are accessed via a low-level delegatecall, the storage layout of the two contracts
+ If state variables are accessed via a low-level delegatecall, the storage layout of the two contracts
must align in order for the called contract to correctly access the storage variables of the calling contract by name.
This is of course not the case if storage pointers are passed as function arguments as in the case for
the high-level libraries.
+.. note::
+ Prior to version 0.5.0, ``.call``, ``.delegatecall`` and ``.staticcall`` only returned the
+ success condition and not the return data.
.. note::
- The use of ``callcode`` is discouraged and will be removed in the future.
+ Prior to version 0.5.0, there was a member called ``callcode`` with similar but slightly different
+ semantics than ``delegatecall``.
+
.. index:: this, selfdestruct
@@ -212,8 +235,9 @@ Contract Related
``selfdestruct(address payable recipient)``:
destroy the current contract, sending its funds to the given :ref:`address`
-``suicide(address payable recipient)``:
- deprecated alias to ``selfdestruct``
-
Furthermore, all functions of the current contract are callable directly including the current function.
+.. note::
+ Prior to version 0.5.0, there was a function called ``suicide`` with the same
+ semantics as ``selfdestruct``.
+
diff --git a/libjulia/backends/evm/AbstractAssembly.h b/libjulia/backends/evm/AbstractAssembly.h
index 6b1b5c23..b6818923 100644
--- a/libjulia/backends/evm/AbstractAssembly.h
+++ b/libjulia/backends/evm/AbstractAssembly.h
@@ -103,7 +103,7 @@ enum class IdentifierContext { LValue, RValue };
struct ExternalIdentifierAccess
{
using Resolver = std::function<size_t(solidity::assembly::Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
- /// Resolve a an external reference given by the identifier in the given context.
+ /// Resolve an external reference given by the identifier in the given context.
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
Resolver resolve;
using CodeGenerator = std::function<void(solidity::assembly::Identifier const&, IdentifierContext, julia::AbstractAssembly&)>;
diff --git a/libsolidity/analysis/SemVerHandler.cpp b/libsolidity/analysis/SemVerHandler.cpp
index 42186396..29f6d5de 100644
--- a/libsolidity/analysis/SemVerHandler.cpp
+++ b/libsolidity/analysis/SemVerHandler.cpp
@@ -106,18 +106,22 @@ bool SemVerMatchExpression::MatchComponent::matches(SemVerVersion const& _versio
}
if (cmp == 0 && !_version.prerelease.empty() && didCompare)
cmp = -1;
- if (prefix == Token::Assign)
+
+ switch (prefix)
+ {
+ case Token::Assign:
return cmp == 0;
- else if (prefix == Token::LessThan)
+ case Token::LessThan:
return cmp < 0;
- else if (prefix == Token::LessThanOrEqual)
+ case Token::LessThanOrEqual:
return cmp <= 0;
- else if (prefix == Token::GreaterThan)
+ case Token::GreaterThan:
return cmp > 0;
- else if (prefix == Token::GreaterThanOrEqual)
+ case Token::GreaterThanOrEqual:
return cmp >= 0;
- else
+ default:
solAssert(false, "Invalid SemVer expression");
+ }
return false;
}
}
@@ -196,21 +200,22 @@ SemVerMatchExpression::MatchComponent SemVerMatchExpressionParser::parseMatchCom
{
SemVerMatchExpression::MatchComponent component;
Token::Value token = currentToken();
- if (
- token == Token::BitXor ||
- token == Token::BitNot ||
- token == Token::LessThan ||
- token == Token::LessThanOrEqual||
- token == Token::GreaterThan ||
- token == Token::GreaterThanOrEqual ||
- token == Token::Assign
- )
+
+ switch (token)
{
+ case Token::BitXor:
+ case Token::BitNot:
+ case Token::LessThan:
+ case Token::LessThanOrEqual:
+ case Token::GreaterThan:
+ case Token::GreaterThanOrEqual:
+ case Token::Assign:
component.prefix = token;
nextToken();
- }
- else
+ break;
+ default:
component.prefix = Token::Assign;
+ }
component.levelsPresent = 0;
while (component.levelsPresent < 3)
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 3056561b..c42a0068 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1778,9 +1778,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
}
if (resultType->category() == Type::Category::Address)
{
- bool payable = true;
- if (auto const* contractType = dynamic_cast<ContractType const*>(argType.get()))
- payable = contractType->isPayable();
+ bool payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
resultType = make_shared<AddressType>(payable ? StateMutability::Payable : StateMutability::NonPayable);
}
}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 56735698..c97ee657 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -666,7 +666,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return TypePointer();
}
- auto commonType = Type::commonType(shared_from_this(), _other); //might be a integer or fixed point
+ auto commonType = Type::commonType(shared_from_this(), _other); //might be an integer or fixed point
if (!commonType)
return TypePointer();
@@ -2126,8 +2126,11 @@ bool StructType::canBeUsedExternally(bool _inLibrary) const
// passed by value and thus the encoding does not differ, but it will disallow
// mappings.
for (auto const& var: m_struct.members())
+ {
+ solAssert(var->annotation().type, "");
if (!var->annotation().type->canBeUsedExternally(false))
return false;
+ }
}
return true;
}
@@ -2641,8 +2644,8 @@ bool FunctionType::operator==(Type const& _other) const
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- if (m_kind == Kind::External && _convertTo.category() == Category::Address)
- return true;
+ if (m_kind == Kind::External && _convertTo == AddressType::address())
+ return true;
return _convertTo.category() == category();
}
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index c1996777..b53c5a5e 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -280,6 +280,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
for (auto const& url: sources[sourceName]["urls"])
{
+ if (!url.isString())
+ return formatFatalError("JSONError", "URL must be a string.");
ReadCallback::Result result = m_readFile(url.asString());
if (result.success)
{
@@ -320,7 +322,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
if (settings.isMember("evmVersion"))
{
- boost::optional<EVMVersion> version = EVMVersion::fromString(settings.get("evmVersion", {}).asString());
+ if (!settings["evmVersion"].isString())
+ return formatFatalError("JSONError", "evmVersion must be a string.");
+ boost::optional<EVMVersion> version = EVMVersion::fromString(settings["evmVersion"].asString());
if (!version)
return formatFatalError("JSONError", "Invalid EVM version requested.");
m_compilerStack.setEVMVersion(*version);
@@ -329,6 +333,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
vector<CompilerStack::Remapping> remappings;
for (auto const& remapping: settings.get("remappings", Json::Value()))
{
+ if (!remapping.isString())
+ return formatFatalError("JSONError", "Remapping entry must be a string.");
if (auto r = CompilerStack::parseRemapping(remapping.asString()))
remappings.emplace_back(std::move(*r));
else
@@ -349,9 +355,11 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
{
auto const& jsonSourceName = jsonLibraries[sourceName];
if (!jsonSourceName.isObject())
- return formatFatalError("JSONError", "library entry is not a JSON object.");
+ return formatFatalError("JSONError", "Library entry is not a JSON object.");
for (auto const& library: jsonSourceName.getMemberNames())
{
+ if (!jsonSourceName[library].isString())
+ return formatFatalError("JSONError", "Library address must be a string.");
string address = jsonSourceName[library].asString();
if (!boost::starts_with(address, "0x"))
diff --git a/scripts/check_style.sh b/scripts/check_style.sh
new file mode 100755
index 00000000..a8557a54
--- /dev/null
+++ b/scripts/check_style.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+REPO_ROOT="$(dirname "$0")"/..
+
+(
+cd $REPO_ROOT
+WHITESPACE=$(git grep -n -I -E "^.*[[:space:]]+$" | grep -v "test/libsolidity/ASTJSON\|test/compilationTests/zeppelin/LICENSE")
+
+if [[ "$WHITESPACE" != "" ]]
+then
+ echo "Error: Trailing whitespace found:" >&2
+ echo "$WHITESPACE" >&2
+ exit 1
+fi
+)
+
+(
+cd $REPO_ROOT
+FORMATERROR=$(
+(
+git grep -nIE "\<(if|for)\(" -- '*.h' '*.cpp'
+git grep -nIE "\<if\>\s*\(.*\)\s*\{\s*$" -- '*.h' '*.cpp'
+) | egrep -v "^[a-zA-Z\./]*:[0-9]*:\s*\/(\/|\*)" | egrep -v "^test/"
+)
+
+if [[ "$FORMATERROR" != "" ]]
+then
+ echo "Error: Format error for if/for:" >&2
+ echo "$FORMATERROR" >&2
+ exit 1
+fi
+)
diff --git a/scripts/detect_trailing_whitespace.sh b/scripts/detect_trailing_whitespace.sh
deleted file mode 100755
index 1a136a10..00000000
--- a/scripts/detect_trailing_whitespace.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-REPO_ROOT="$(dirname "$0")"/..
-
-(
-cd $REPO_ROOT
-WHITESPACE=$(git grep -n -I -E "^.*[[:space:]]+$" | grep -v "test/libsolidity/ASTJSON\|test/compilationTests/zeppelin/LICENSE")
-
-if [[ "$WHITESPACE" != "" ]]
-then
- echo "Error: Trailing whitespace found:" >&2
- echo "$WHITESPACE" >&2
- exit 1
-fi
-)
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 3aa1dc24..d34bacda 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -640,7 +640,7 @@ BOOST_AUTO_TEST_CASE(libraries_invalid_entry)
}
)";
Json::Value result = compile(input);
- BOOST_CHECK(containsError(result, "JSONError", "library entry is not a JSON object."));
+ BOOST_CHECK(containsError(result, "JSONError", "Library entry is not a JSON object."));
}
BOOST_AUTO_TEST_CASE(libraries_invalid_hex)
diff --git a/test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol b/test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol
new file mode 100644
index 00000000..adffb14b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f() public view returns (address payable) {
+ return address(this.f);
+ }
+}
+// ----
+// TypeError: (85-100): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol b/test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol
new file mode 100644
index 00000000..1e755033
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f(address a) public pure returns (address payable) {
+ return address(address(a));
+ }
+}
+// ----
+// TypeError: (94-113): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol
new file mode 100644
index 00000000..ef87ac55
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f(bytes32 x) public pure returns (address payable) {
+ return address(x);
+ }
+}
+// ----
+// TypeError: (94-104): Explicit type conversion not allowed from "bytes32" to "address".
+// TypeError: (94-104): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol
new file mode 100644
index 00000000..2aa60251
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f(bytes10 x) public pure returns (address payable) {
+ return address(x);
+ }
+}
+// ----
+// TypeError: (94-104): Explicit type conversion not allowed from "bytes10" to "address".
+// TypeError: (94-104): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol
new file mode 100644
index 00000000..5b6a6714
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(bytes20 x) public pure returns (address payable) {
+ return address(x);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol
new file mode 100644
index 00000000..9a33985a
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(uint x) public pure returns (address payable) {
+ return address(x);
+ }
+}