mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into HEAD
This commit is contained in:
commit
07c67b98f6
@ -27,6 +27,9 @@ Compiler Features:
|
|||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
* Type Checker: Disallow constructor of the same class to be used as modifier
|
||||||
|
* Code Generator: Fixed a faulty assert that would wrongly trigger for array sizes exceeding unsigned integer
|
||||||
|
* Type Checker: Treat magic variables as unknown identifiers in inline assembly
|
||||||
|
|
||||||
|
|
||||||
### 0.5.13 (unreleased)
|
### 0.5.13 (unreleased)
|
||||||
|
@ -292,27 +292,27 @@ Consider you have the following pre-0.5.0 contract already deployed:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
// This will not compile with the current version of the compiler
|
// This will not compile with the current version of the compiler
|
||||||
pragma solidity ^0.4.25;
|
pragma solidity ^0.4.25;
|
||||||
contract OldContract {
|
contract OldContract {
|
||||||
function someOldFunction(uint8 a) {
|
function someOldFunction(uint8 a) {
|
||||||
//...
|
//...
|
||||||
}
|
}
|
||||||
function anotherOldFunction() constant returns (bool) {
|
function anotherOldFunction() constant returns (bool) {
|
||||||
//...
|
//...
|
||||||
}
|
}
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
This will no longer compile with Solidity v0.5.0. However, you can define a compatible interface for it:
|
This will no longer compile with Solidity v0.5.0. However, you can define a compatible interface for it:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.5.0 <0.7.0;
|
pragma solidity >=0.5.0 <0.7.0;
|
||||||
interface OldContract {
|
interface OldContract {
|
||||||
function someOldFunction(uint8 a) external;
|
function someOldFunction(uint8 a) external;
|
||||||
function anotherOldFunction() external returns (bool);
|
function anotherOldFunction() external returns (bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that we did not declare ``anotherOldFunction`` to be ``view``, despite it being declared ``constant`` in the original
|
Note that we did not declare ``anotherOldFunction`` to be ``view``, despite it being declared ``constant`` in the original
|
||||||
contract. This is due to the fact that starting with Solidity v0.5.0 ``staticcall`` is used to call ``view`` functions.
|
contract. This is due to the fact that starting with Solidity v0.5.0 ``staticcall`` is used to call ``view`` functions.
|
||||||
@ -325,19 +325,19 @@ Given the interface defined above, you can now easily use the already deployed p
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.5.0 <0.7.0;
|
pragma solidity >=0.5.0 <0.7.0;
|
||||||
|
|
||||||
interface OldContract {
|
interface OldContract {
|
||||||
function someOldFunction(uint8 a) external;
|
function someOldFunction(uint8 a) external;
|
||||||
function anotherOldFunction() external returns (bool);
|
function anotherOldFunction() external returns (bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
contract NewContract {
|
contract NewContract {
|
||||||
function doSomething(OldContract a) public returns (bool) {
|
function doSomething(OldContract a) public returns (bool) {
|
||||||
a.someOldFunction(0x42);
|
a.someOldFunction(0x42);
|
||||||
return a.anotherOldFunction();
|
return a.anotherOldFunction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Similarly, pre-0.5.0 libraries can be used by defining the functions of the library without implementation and
|
Similarly, pre-0.5.0 libraries can be used by defining the functions of the library without implementation and
|
||||||
supplying the address of the pre-0.5.0 library during linking (see :ref:`commandline-compiler` for how to use the
|
supplying the address of the pre-0.5.0 library during linking (see :ref:`commandline-compiler` for how to use the
|
||||||
@ -345,17 +345,17 @@ commandline compiler for linking):
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.5.0 <0.7.0;
|
pragma solidity >=0.5.0 <0.7.0;
|
||||||
|
|
||||||
library OldLibrary {
|
library OldLibrary {
|
||||||
function someFunction(uint8 a) public returns(bool);
|
function someFunction(uint8 a) public returns(bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
contract NewContract {
|
contract NewContract {
|
||||||
function f(uint8 a) public returns (bool) {
|
function f(uint8 a) public returns (bool) {
|
||||||
return OldLibrary.someFunction(a);
|
return OldLibrary.someFunction(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
@ -368,144 +368,144 @@ Old version:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
// This will not compile
|
// This will not compile
|
||||||
pragma solidity ^0.4.25;
|
pragma solidity ^0.4.25;
|
||||||
|
|
||||||
contract OtherContract {
|
contract OtherContract {
|
||||||
uint x;
|
uint x;
|
||||||
function f(uint y) external {
|
function f(uint y) external {
|
||||||
x = y;
|
x = y;
|
||||||
}
|
}
|
||||||
function() payable external {}
|
function() payable external {}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract Old {
|
contract Old {
|
||||||
OtherContract other;
|
OtherContract other;
|
||||||
uint myNumber;
|
uint myNumber;
|
||||||
|
|
||||||
// Function mutability not provided, not an error.
|
// Function mutability not provided, not an error.
|
||||||
function someInteger() internal returns (uint) { return 2; }
|
function someInteger() internal returns (uint) { return 2; }
|
||||||
|
|
||||||
// Function visibility not provided, not an error.
|
// Function visibility not provided, not an error.
|
||||||
// Function mutability not provided, not an error.
|
// Function mutability not provided, not an error.
|
||||||
function f(uint x) returns (bytes) {
|
function f(uint x) returns (bytes) {
|
||||||
// Var is fine in this version.
|
// Var is fine in this version.
|
||||||
var z = someInteger();
|
var z = someInteger();
|
||||||
x += z;
|
x += z;
|
||||||
// Throw is fine in this version.
|
// Throw is fine in this version.
|
||||||
if (x > 100)
|
if (x > 100)
|
||||||
throw;
|
throw;
|
||||||
bytes b = new bytes(x);
|
bytes b = new bytes(x);
|
||||||
y = -3 >> 1;
|
y = -3 >> 1;
|
||||||
// y == -1 (wrong, should be -2)
|
// y == -1 (wrong, should be -2)
|
||||||
do {
|
do {
|
||||||
x += 1;
|
x += 1;
|
||||||
if (x > 10) continue;
|
if (x > 10) continue;
|
||||||
// 'Continue' causes an infinite loop.
|
// 'Continue' causes an infinite loop.
|
||||||
} while (x < 11);
|
} while (x < 11);
|
||||||
// Call returns only a Bool.
|
// Call returns only a Bool.
|
||||||
bool success = address(other).call("f");
|
bool success = address(other).call("f");
|
||||||
if (!success)
|
if (!success)
|
||||||
revert();
|
revert();
|
||||||
else {
|
else {
|
||||||
// Local variables could be declared after their use.
|
// Local variables could be declared after their use.
|
||||||
int y;
|
int y;
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need for an explicit data location for 'arr'
|
// No need for an explicit data location for 'arr'
|
||||||
function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
|
function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
|
||||||
otherContract.transfer(1 ether);
|
otherContract.transfer(1 ether);
|
||||||
|
|
||||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||||
// the first 4 bytes of x will be lost. This might lead to
|
// the first 4 bytes of x will be lost. This might lead to
|
||||||
// unexpected behavior since bytesX are right padded.
|
// unexpected behavior since bytesX are right padded.
|
||||||
uint32 y = uint32(x);
|
uint32 y = uint32(x);
|
||||||
myNumber += y + msg.value;
|
myNumber += y + msg.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
New version:
|
New version:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.5.0 <0.7.0;
|
pragma solidity >=0.5.0 <0.7.0;
|
||||||
|
|
||||||
contract OtherContract {
|
contract OtherContract {
|
||||||
uint x;
|
uint x;
|
||||||
function f(uint y) external {
|
function f(uint y) external {
|
||||||
x = y;
|
x = y;
|
||||||
}
|
}
|
||||||
function() payable external {}
|
function() payable external {}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract New {
|
contract New {
|
||||||
OtherContract other;
|
OtherContract other;
|
||||||
uint myNumber;
|
uint myNumber;
|
||||||
|
|
||||||
// Function mutability must be specified.
|
// Function mutability must be specified.
|
||||||
function someInteger() internal pure returns (uint) { return 2; }
|
function someInteger() internal pure returns (uint) { return 2; }
|
||||||
|
|
||||||
// Function visibility must be specified.
|
// Function visibility must be specified.
|
||||||
// Function mutability must be specified.
|
// Function mutability must be specified.
|
||||||
function f(uint x) public returns (bytes memory) {
|
function f(uint x) public returns (bytes memory) {
|
||||||
// The type must now be explicitly given.
|
// The type must now be explicitly given.
|
||||||
uint z = someInteger();
|
uint z = someInteger();
|
||||||
x += z;
|
x += z;
|
||||||
// Throw is now disallowed.
|
// Throw is now disallowed.
|
||||||
require(x > 100);
|
require(x > 100);
|
||||||
int y = -3 >> 1;
|
int y = -3 >> 1;
|
||||||
// y == -2 (correct)
|
require(y == -2);
|
||||||
do {
|
do {
|
||||||
x += 1;
|
x += 1;
|
||||||
if (x > 10) continue;
|
if (x > 10) continue;
|
||||||
// 'Continue' jumps to the condition below.
|
// 'Continue' jumps to the condition below.
|
||||||
} while (x < 11);
|
} while (x < 11);
|
||||||
|
|
||||||
// Call returns (bool, bytes).
|
// Call returns (bool, bytes).
|
||||||
// Data location must be specified.
|
// Data location must be specified.
|
||||||
(bool success, bytes memory data) = address(other).call("f");
|
(bool success, bytes memory data) = address(other).call("f");
|
||||||
if (!success)
|
if (!success)
|
||||||
revert();
|
revert();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
using address_make_payable for address;
|
using address_make_payable for address;
|
||||||
// Data location for 'arr' must be specified
|
// Data location for 'arr' must be specified
|
||||||
function g(uint[] memory arr, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
|
function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
|
||||||
// 'otherContract.transfer' is not provided.
|
// 'otherContract.transfer' is not provided.
|
||||||
// Since the code of 'OtherContract' is known and has the fallback
|
// Since the code of 'OtherContract' is known and has the fallback
|
||||||
// function, address(otherContract) has type 'address payable'.
|
// function, address(otherContract) has type 'address payable'.
|
||||||
address(otherContract).transfer(1 ether);
|
address(otherContract).transfer(1 ether);
|
||||||
|
|
||||||
// 'unknownContract.transfer' is not provided.
|
// 'unknownContract.transfer' is not provided.
|
||||||
// 'address(unknownContract).transfer' is not provided
|
// 'address(unknownContract).transfer' is not provided
|
||||||
// since 'address(unknownContract)' is not 'address payable'.
|
// since 'address(unknownContract)' is not 'address payable'.
|
||||||
// If the function takes an 'address' which you want to send
|
// If the function takes an 'address' which you want to send
|
||||||
// funds to, you can convert it to 'address payable' via 'uint160'.
|
// funds to, you can convert it to 'address payable' via 'uint160'.
|
||||||
// Note: This is not recommended and the explicit type
|
// Note: This is not recommended and the explicit type
|
||||||
// 'address payable' should be used whenever possible.
|
// 'address payable' should be used whenever possible.
|
||||||
// To increase clarity, we suggest the use of a library for
|
// To increase clarity, we suggest the use of a library for
|
||||||
// the conversion (provided after the contract in this example).
|
// the conversion (provided after the contract in this example).
|
||||||
address payable addr = unknownContract.make_payable();
|
address payable addr = unknownContract.make_payable();
|
||||||
require(addr.send(1 ether));
|
require(addr.send(1 ether));
|
||||||
|
|
||||||
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
|
||||||
// the conversion is not allowed.
|
// the conversion is not allowed.
|
||||||
// We need to convert to a common size first:
|
// We need to convert to a common size first:
|
||||||
bytes4 x4 = bytes4(x); // Padding happens on the right
|
bytes4 x4 = bytes4(x); // Padding happens on the right
|
||||||
uint32 y = uint32(x4); // Conversion is consistent
|
uint32 y = uint32(x4); // Conversion is consistent
|
||||||
// 'msg.value' cannot be used in a 'non-payable' function.
|
// 'msg.value' cannot be used in a 'non-payable' function.
|
||||||
// We need to make the function payable
|
// We need to make the function payable
|
||||||
myNumber += y + msg.value;
|
myNumber += y + msg.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can define a library for explicitly converting ``address``
|
// We can define a library for explicitly converting ``address``
|
||||||
// to ``address payable`` as a workaround.
|
// to ``address payable`` as a workaround.
|
||||||
library address_make_payable {
|
library address_make_payable {
|
||||||
function make_payable(address x) internal pure returns (address payable) {
|
function make_payable(address x) internal pure returns (address payable) {
|
||||||
return address(uint160(x));
|
return address(uint160(x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,24 +150,24 @@ to write a function, for example:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.4.0 <0.7.0;
|
pragma solidity >=0.4.0 <0.7.0;
|
||||||
|
|
||||||
contract arrayExample {
|
contract arrayExample {
|
||||||
// public state variable
|
// public state variable
|
||||||
uint[] public myArray;
|
uint[] public myArray;
|
||||||
|
|
||||||
// Getter function generated by the compiler
|
// Getter function generated by the compiler
|
||||||
/*
|
/*
|
||||||
function myArray(uint i) returns (uint) {
|
function myArray(uint i) public view returns (uint) {
|
||||||
return myArray[i];
|
return myArray[i];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// function that returns entire array
|
||||||
|
function getArray() public view returns (uint[] memory) {
|
||||||
|
return myArray;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// function that returns entire array
|
|
||||||
function getArray() returns (uint[] memory) {
|
|
||||||
return myArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Now you can use ``getArray()`` to retrieve the entire array, instead of
|
Now you can use ``getArray()`` to retrieve the entire array, instead of
|
||||||
``myArray(i)``, which returns a single element per call.
|
``myArray(i)``, which returns a single element per call.
|
||||||
|
@ -37,7 +37,7 @@ breaking changes. These releases always have versions of the form
|
|||||||
|
|
||||||
The version pragma is used as follows::
|
The version pragma is used as follows::
|
||||||
|
|
||||||
pragma solidity ^0.5.2;
|
pragma solidity ^0.5.2;
|
||||||
|
|
||||||
A source file with the line above does not compile with a compiler earlier than version 0.5.2,
|
A source file with the line above does not compile with a compiler earlier than version 0.5.2,
|
||||||
and it also does not work on a compiler starting from version 0.6.0 (this
|
and it also does not work on a compiler starting from version 0.6.0 (this
|
||||||
|
@ -49,22 +49,22 @@ The following example shows a contract and a function using all available tags.
|
|||||||
|
|
||||||
.. code:: solidity
|
.. code:: solidity
|
||||||
|
|
||||||
pragma solidity ^0.5.6;
|
pragma solidity ^0.5.6;
|
||||||
|
|
||||||
/// @title A simulator for trees
|
/// @title A simulator for trees
|
||||||
/// @author Larry A. Gardner
|
/// @author Larry A. Gardner
|
||||||
/// @notice You can use this contract for only the most basic simulation
|
/// @notice You can use this contract for only the most basic simulation
|
||||||
/// @dev All function calls are currently implemented without side effects
|
/// @dev All function calls are currently implemented without side effects
|
||||||
contract Tree {
|
contract Tree {
|
||||||
/// @author Mary A. Botanist
|
/// @author Mary A. Botanist
|
||||||
/// @notice Calculate tree age in years, rounded up, for live trees
|
/// @notice Calculate tree age in years, rounded up, for live trees
|
||||||
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
||||||
/// @param rings The number of rings from dendrochronological sample
|
/// @param rings The number of rings from dendrochronological sample
|
||||||
/// @return age in years, rounded up for partial years
|
/// @return age in years, rounded up for partial years
|
||||||
function age(uint256 rings) external pure returns (uint256) {
|
function age(uint256 rings) external pure returns (uint256) {
|
||||||
return rings + 1;
|
return rings + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.. _header-tags:
|
.. _header-tags:
|
||||||
|
|
||||||
|
@ -499,26 +499,26 @@ not mean loss of proving power.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.5.0;
|
pragma solidity >=0.5.0;
|
||||||
pragma experimental SMTChecker;
|
pragma experimental SMTChecker;
|
||||||
|
|
||||||
contract Recover
|
contract Recover
|
||||||
{
|
{
|
||||||
function f(
|
function f(
|
||||||
bytes32 hash,
|
bytes32 hash,
|
||||||
uint8 _v1, uint8 _v2,
|
uint8 _v1, uint8 _v2,
|
||||||
bytes32 _r1, bytes32 _r2,
|
bytes32 _r1, bytes32 _r2,
|
||||||
bytes32 _s1, bytes32 _s2
|
bytes32 _s1, bytes32 _s2
|
||||||
) public pure returns (address) {
|
) public pure returns (address) {
|
||||||
address a1 = ecrecover(hash, _v1, _r1, _s1);
|
address a1 = ecrecover(hash, _v1, _r1, _s1);
|
||||||
require(_v1 == _v2);
|
require(_v1 == _v2);
|
||||||
require(_r1 == _r2);
|
require(_r1 == _r2);
|
||||||
require(_s1 == _s2);
|
require(_s1 == _s2);
|
||||||
address a2 = ecrecover(hash, _v2, _r2, _s2);
|
address a2 = ecrecover(hash, _v2, _r2, _s2);
|
||||||
assert(a1 == a2);
|
assert(a1 == a2);
|
||||||
return a1;
|
return a1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
In the example above, the SMTChecker is not expressive enough to actually
|
In the example above, the SMTChecker is not expressive enough to actually
|
||||||
compute ``ecrecover``, but by modelling the function calls as uninterpreted
|
compute ``ecrecover``, but by modelling the function calls as uninterpreted
|
||||||
@ -552,34 +552,34 @@ types.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
pragma solidity >=0.5.0;
|
pragma solidity >=0.5.0;
|
||||||
pragma experimental SMTChecker;
|
pragma experimental SMTChecker;
|
||||||
// This will not compile
|
// This will report a warning
|
||||||
contract Aliasing
|
contract Aliasing
|
||||||
{
|
{
|
||||||
uint[] array;
|
uint[] array;
|
||||||
function f(
|
function f(
|
||||||
uint[] memory a,
|
uint[] memory a,
|
||||||
uint[] memory b,
|
uint[] memory b,
|
||||||
uint[][] memory c,
|
uint[][] memory c,
|
||||||
uint[] storage d
|
uint[] storage d
|
||||||
) internal view {
|
) internal view {
|
||||||
require(array[0] == 42);
|
require(array[0] == 42);
|
||||||
require(a[0] == 2);
|
require(a[0] == 2);
|
||||||
require(c[0][0] == 2);
|
require(c[0][0] == 2);
|
||||||
require(d[0] == 2);
|
require(d[0] == 2);
|
||||||
b[0] = 1;
|
b[0] = 1;
|
||||||
// Erasing knowledge about memory references should not
|
// Erasing knowledge about memory references should not
|
||||||
// erase knowledge about state variables.
|
// erase knowledge about state variables.
|
||||||
assert(array[0] == 42);
|
assert(array[0] == 42);
|
||||||
// Fails because `a == b` is possible.
|
// Fails because `a == b` is possible.
|
||||||
assert(a[0] == 2);
|
assert(a[0] == 2);
|
||||||
// Fails because `c[i] == b` is possible.
|
// Fails because `c[i] == b` is possible.
|
||||||
assert(c[0][0] == 2);
|
assert(c[0][0] == 2);
|
||||||
assert(d[0] == 2);
|
assert(d[0] == 2);
|
||||||
assert(b[0] == 1);
|
assert(b[0] == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
After the assignment to ``b[0]``, we need to clear knowledge about ``a`` since
|
After the assignment to ``b[0]``, we need to clear knowledge about ``a`` since
|
||||||
it has the same type (``uint[]``) and data location (memory). We also need to
|
it has the same type (``uint[]``) and data location (memory). We also need to
|
||||||
|
@ -388,11 +388,13 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
|||||||
set<Declaration const*> modifiers;
|
set<Declaration const*> modifiers;
|
||||||
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
|
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
|
||||||
{
|
{
|
||||||
|
auto baseContracts = dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts;
|
||||||
|
// Delete first base which is just the main contract itself
|
||||||
|
baseContracts.erase(baseContracts.begin());
|
||||||
|
|
||||||
visitManually(
|
visitManually(
|
||||||
*modifier,
|
*modifier,
|
||||||
_function.isConstructor() ?
|
_function.isConstructor() ? baseContracts : vector<ContractDefinition const*>()
|
||||||
dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts :
|
|
||||||
vector<ContractDefinition const*>()
|
|
||||||
);
|
);
|
||||||
Declaration const* decl = &dereference(*modifier->name());
|
Declaration const* decl = &dereference(*modifier->name());
|
||||||
if (modifiers.count(decl))
|
if (modifiers.count(decl))
|
||||||
@ -520,7 +522,12 @@ void TypeChecker::visitManually(
|
|||||||
_modifier.arguments() ? *_modifier.arguments() : std::vector<ASTPointer<Expression>>();
|
_modifier.arguments() ? *_modifier.arguments() : std::vector<ASTPointer<Expression>>();
|
||||||
for (ASTPointer<Expression> const& argument: arguments)
|
for (ASTPointer<Expression> const& argument: arguments)
|
||||||
argument->accept(*this);
|
argument->accept(*this);
|
||||||
_modifier.name()->accept(*this);
|
|
||||||
|
{
|
||||||
|
m_insideModifierInvocation = true;
|
||||||
|
ScopeGuard resetFlag{[&] () { m_insideModifierInvocation = false; }};
|
||||||
|
_modifier.name()->accept(*this);
|
||||||
|
}
|
||||||
|
|
||||||
auto const* declaration = &dereference(*_modifier.name());
|
auto const* declaration = &dereference(*_modifier.name());
|
||||||
vector<ASTPointer<VariableDeclaration>> emptyParameterList;
|
vector<ASTPointer<VariableDeclaration>> emptyParameterList;
|
||||||
@ -693,6 +700,9 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
|
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||||
|
return size_t(-1);
|
||||||
|
|
||||||
m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly.");
|
m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||||
return size_t(-1);
|
return size_t(-1);
|
||||||
}
|
}
|
||||||
@ -2595,15 +2605,24 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
|
if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_identifier.location(),
|
_identifier.location(),
|
||||||
"\"sha3\" has been deprecated in favour of \"keccak256\""
|
"\"sha3\" has been deprecated in favour of \"keccak256\"."
|
||||||
);
|
);
|
||||||
else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct)
|
else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_identifier.location(),
|
_identifier.location(),
|
||||||
"\"suicide\" has been deprecated in favour of \"selfdestruct\""
|
"\"suicide\" has been deprecated in favour of \"selfdestruct\"."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_insideModifierInvocation)
|
||||||
|
if (ModifierType const* type = dynamic_cast<decltype(type)>(_identifier.annotation().type))
|
||||||
|
{
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
_identifier.location(),
|
||||||
|
"Modifier can only be referenced in function headers."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +168,9 @@ private:
|
|||||||
/// Flag indicating whether we are currently inside a StructDefinition.
|
/// Flag indicating whether we are currently inside a StructDefinition.
|
||||||
bool m_insideStruct = false;
|
bool m_insideStruct = false;
|
||||||
|
|
||||||
|
/// Flag indicating whether we are currently inside the invocation of a modifier
|
||||||
|
bool m_insideModifierInvocation = false;
|
||||||
|
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1861,7 +1861,7 @@ u256 ArrayType::memoryDataSize() const
|
|||||||
solAssert(m_location == DataLocation::Memory, "");
|
solAssert(m_location == DataLocation::Memory, "");
|
||||||
solAssert(!isByteArray(), "");
|
solAssert(!isByteArray(), "");
|
||||||
bigint size = bigint(m_length) * m_baseType->memoryHeadSize();
|
bigint size = bigint(m_length) * m_baseType->memoryHeadSize();
|
||||||
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit u256.");
|
solAssert(size <= numeric_limits<u256>::max(), "Array size does not fit u256.");
|
||||||
return u256(size);
|
return u256(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ struct Literal;
|
|||||||
struct StringLiteral;
|
struct StringLiteral;
|
||||||
struct LocalVariable;
|
struct LocalVariable;
|
||||||
struct GlobalVariable;
|
struct GlobalVariable;
|
||||||
struct Label;
|
|
||||||
struct FunctionCall;
|
struct FunctionCall;
|
||||||
struct BuiltinCall;
|
struct BuiltinCall;
|
||||||
struct LocalAssignment;
|
struct LocalAssignment;
|
||||||
@ -42,11 +41,11 @@ struct Block;
|
|||||||
struct If;
|
struct If;
|
||||||
struct Loop;
|
struct Loop;
|
||||||
struct Break;
|
struct Break;
|
||||||
struct Continue;
|
struct BreakIf;
|
||||||
using Expression = boost::variant<
|
using Expression = boost::variant<
|
||||||
Literal, StringLiteral, LocalVariable, GlobalVariable, Label,
|
Literal, StringLiteral, LocalVariable, GlobalVariable,
|
||||||
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
|
FunctionCall, BuiltinCall, LocalAssignment, GlobalAssignment,
|
||||||
Block, If, Loop, Break, Continue
|
Block, If, Loop, Break, BreakIf
|
||||||
>;
|
>;
|
||||||
|
|
||||||
struct Literal { uint64_t value; };
|
struct Literal { uint64_t value; };
|
||||||
@ -66,7 +65,7 @@ struct If {
|
|||||||
};
|
};
|
||||||
struct Loop { std::string labelName; std::vector<Expression> statements; };
|
struct Loop { std::string labelName; std::vector<Expression> statements; };
|
||||||
struct Break { Label label; };
|
struct Break { Label label; };
|
||||||
struct Continue { Label label; };
|
struct BreakIf { Label label; std::unique_ptr<Expression> condition; };
|
||||||
|
|
||||||
struct VariableDeclaration { std::string variableName; };
|
struct VariableDeclaration { std::string variableName; };
|
||||||
struct GlobalVariableDeclaration { std::string variableName; };
|
struct GlobalVariableDeclaration { std::string variableName; };
|
||||||
|
@ -248,8 +248,7 @@ wasm::Expression EWasmCodeTransform::operator()(ForLoop const& _for)
|
|||||||
|
|
||||||
wasm::Loop loop;
|
wasm::Loop loop;
|
||||||
loop.statements = visit(_for.pre.statements);
|
loop.statements = visit(_for.pre.statements);
|
||||||
loop.statements.emplace_back(wasm::BuiltinCall{"br_if", make_vector<wasm::Expression>(
|
loop.statements.emplace_back(wasm::BreakIf{wasm::Label{breakLabel}, make_unique<wasm::Expression>(
|
||||||
wasm::Label{breakLabel},
|
|
||||||
wasm::BuiltinCall{"i64.eqz", make_vector<wasm::Expression>(
|
wasm::BuiltinCall{"i64.eqz", make_vector<wasm::Expression>(
|
||||||
visitReturnByValue(*_for.condition)
|
visitReturnByValue(*_for.condition)
|
||||||
)}
|
)}
|
||||||
@ -267,7 +266,7 @@ wasm::Expression EWasmCodeTransform::operator()(Break const&)
|
|||||||
|
|
||||||
wasm::Expression EWasmCodeTransform::operator()(Continue const&)
|
wasm::Expression EWasmCodeTransform::operator()(Continue const&)
|
||||||
{
|
{
|
||||||
return wasm::Continue{wasm::Label{m_breakContinueLabelNames.top().second}};
|
return wasm::Break{wasm::Label{m_breakContinueLabelNames.top().second}};
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm::Expression EWasmCodeTransform::operator()(Block const& _block)
|
wasm::Expression EWasmCodeTransform::operator()(Block const& _block)
|
||||||
|
@ -82,11 +82,6 @@ string EWasmToText::operator()(wasm::GlobalVariable const& _identifier)
|
|||||||
return "(get_global $" + _identifier.name + ")";
|
return "(get_global $" + _identifier.name + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
string EWasmToText::operator()(wasm::Label const& _label)
|
|
||||||
{
|
|
||||||
return "$" + _label.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
string EWasmToText::operator()(wasm::BuiltinCall const& _builtinCall)
|
string EWasmToText::operator()(wasm::BuiltinCall const& _builtinCall)
|
||||||
{
|
{
|
||||||
string args = joinTransformed(_builtinCall.arguments);
|
string args = joinTransformed(_builtinCall.arguments);
|
||||||
@ -128,9 +123,9 @@ string EWasmToText::operator()(wasm::Break const& _break)
|
|||||||
return "(break $" + _break.label.name + ")\n";
|
return "(break $" + _break.label.name + ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
string EWasmToText::operator()(wasm::Continue const& _continue)
|
string EWasmToText::operator()(wasm::BreakIf const& _break)
|
||||||
{
|
{
|
||||||
return "(continue $" + _continue.label.name + ")\n";
|
return "(br_if $" + _break.label.name + " " + visit(*_break.condition) + ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
string EWasmToText::operator()(wasm::Block const& _block)
|
string EWasmToText::operator()(wasm::Block const& _block)
|
||||||
|
@ -42,7 +42,6 @@ public:
|
|||||||
std::string operator()(wasm::StringLiteral const& _literal);
|
std::string operator()(wasm::StringLiteral const& _literal);
|
||||||
std::string operator()(wasm::LocalVariable const& _identifier);
|
std::string operator()(wasm::LocalVariable const& _identifier);
|
||||||
std::string operator()(wasm::GlobalVariable const& _identifier);
|
std::string operator()(wasm::GlobalVariable const& _identifier);
|
||||||
std::string operator()(wasm::Label const& _label);
|
|
||||||
std::string operator()(wasm::BuiltinCall const& _builinCall);
|
std::string operator()(wasm::BuiltinCall const& _builinCall);
|
||||||
std::string operator()(wasm::FunctionCall const& _functionCall);
|
std::string operator()(wasm::FunctionCall const& _functionCall);
|
||||||
std::string operator()(wasm::LocalAssignment const& _assignment);
|
std::string operator()(wasm::LocalAssignment const& _assignment);
|
||||||
@ -50,7 +49,7 @@ public:
|
|||||||
std::string operator()(wasm::If const& _if);
|
std::string operator()(wasm::If const& _if);
|
||||||
std::string operator()(wasm::Loop const& _loop);
|
std::string operator()(wasm::Loop const& _loop);
|
||||||
std::string operator()(wasm::Break const& _break);
|
std::string operator()(wasm::Break const& _break);
|
||||||
std::string operator()(wasm::Continue const& _continue);
|
std::string operator()(wasm::BreakIf const& _break);
|
||||||
std::string operator()(wasm::Block const& _block);
|
std::string operator()(wasm::Block const& _block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -39,6 +39,7 @@ def extract_test_cases(path):
|
|||||||
# and abort a line not indented properly.
|
# and abort a line not indented properly.
|
||||||
def extract_docs_cases(path):
|
def extract_docs_cases(path):
|
||||||
inside = False
|
inside = False
|
||||||
|
extractedLines = []
|
||||||
tests = []
|
tests = []
|
||||||
|
|
||||||
# Collect all snippets of indented blocks
|
# Collect all snippets of indented blocks
|
||||||
@ -46,15 +47,23 @@ def extract_docs_cases(path):
|
|||||||
if l != '':
|
if l != '':
|
||||||
if not inside and l.startswith(' '):
|
if not inside and l.startswith(' '):
|
||||||
# start new test
|
# start new test
|
||||||
tests += ['']
|
extractedLines += ['']
|
||||||
inside = l.startswith(' ')
|
inside = l.startswith(' ')
|
||||||
if inside:
|
if inside:
|
||||||
tests[-1] += l + '\n'
|
extractedLines[-1] += l + '\n'
|
||||||
# Filter all tests that do not contain Solidity
|
|
||||||
return [
|
codeStart = "(pragma solidity|contract.*{|library.*{|interface.*{)"
|
||||||
test for test in tests
|
|
||||||
if re.search(r'^ [ ]*(pragma solidity|contract |library |interface )', test, re.MULTILINE)
|
# Filter all tests that do not contain Solidity or are intended incorrectly.
|
||||||
]
|
for lines in extractedLines:
|
||||||
|
if re.search(r'^\s{0,3}' + codeStart, lines, re.MULTILINE):
|
||||||
|
print("Intendation error in " + path + ":")
|
||||||
|
print(lines)
|
||||||
|
exit(1)
|
||||||
|
if re.search(r'^\s{4}' + codeStart, lines, re.MULTILINE):
|
||||||
|
tests.append(lines)
|
||||||
|
|
||||||
|
return tests
|
||||||
|
|
||||||
def write_cases(f, tests):
|
def write_cases(f, tests):
|
||||||
cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
|
cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
|
||||||
|
@ -90,15 +90,14 @@ function truffle_setup
|
|||||||
|
|
||||||
setup_solcjs "$DIR" "$SOLJSON" "v0.5.0" "solc"
|
setup_solcjs "$DIR" "$SOLJSON" "v0.5.0" "solc"
|
||||||
download_project "$repo" "$branch" "$DIR"
|
download_project "$repo" "$branch" "$DIR"
|
||||||
|
|
||||||
replace_version_pragmas
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function replace_version_pragmas
|
function replace_version_pragmas
|
||||||
{
|
{
|
||||||
# Replace fixed-version pragmas in Gnosis (part of Consensys best practice)
|
# Replace fixed-version pragmas (part of Consensys best practice).
|
||||||
|
# Include all directories to also cover node dependencies.
|
||||||
printLog "Replacing fixed-version pragmas..."
|
printLog "Replacing fixed-version pragmas..."
|
||||||
find contracts test -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity [\^0-9\.]*/pragma solidity >=0.0/'
|
find . test -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity [\^0-9\.]*/pragma solidity >=0.0/'
|
||||||
}
|
}
|
||||||
|
|
||||||
function replace_libsolc_call
|
function replace_libsolc_call
|
||||||
@ -211,6 +210,8 @@ function run_test
|
|||||||
local compile_fn="$1"
|
local compile_fn="$1"
|
||||||
local test_fn="$2"
|
local test_fn="$2"
|
||||||
|
|
||||||
|
replace_version_pragmas
|
||||||
|
|
||||||
printLog "Running compile function..."
|
printLog "Running compile function..."
|
||||||
$compile_fn
|
$compile_fn
|
||||||
|
|
||||||
|
10
test/libsolidity/syntaxTests/array/length/not_too_large.sol
Normal file
10
test/libsolidity/syntaxTests/array/length/not_too_large.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Used to cause ICE because of a too strict assert
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
contract C {
|
||||||
|
struct S { uint a; T[222222222222222222222222222] sub; }
|
||||||
|
struct T { uint[] x; }
|
||||||
|
function f() public returns (uint, S memory) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (52-85): Experimental features are turned on. Do not use experimental features on live deployments.
|
@ -8,5 +8,5 @@ contract test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (58-62): "sha3" has been deprecated in favour of "keccak256"
|
// TypeError: (58-62): "sha3" has been deprecated in favour of "keccak256".
|
||||||
// TypeError: (101-108): "suicide" has been deprecated in favour of "selfdestruct"
|
// TypeError: (101-108): "suicide" has been deprecated in favour of "selfdestruct".
|
||||||
|
@ -5,4 +5,4 @@ contract C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (60-64): "sha3" has been deprecated in favour of "keccak256"
|
// TypeError: (60-64): "sha3" has been deprecated in favour of "keccak256".
|
||||||
|
@ -5,4 +5,4 @@ contract C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (60-67): "suicide" has been deprecated in favour of "selfdestruct"
|
// TypeError: (60-67): "suicide" has been deprecated in favour of "selfdestruct".
|
||||||
|
@ -2,12 +2,18 @@ contract C {
|
|||||||
function f() public {
|
function f() public {
|
||||||
assembly {
|
assembly {
|
||||||
super := 1
|
super := 1
|
||||||
|
this := 1
|
||||||
|
msg := 1
|
||||||
|
block := 1
|
||||||
f := 1
|
f := 1
|
||||||
C := 1
|
C := 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (58-63): Only local variables can be assigned to in inline assembly.
|
// DeclarationError: (58-63): Variable not found or variable not lvalue.
|
||||||
// TypeError: (75-76): Only local variables can be assigned to in inline assembly.
|
// DeclarationError: (75-79): Variable not found or variable not lvalue.
|
||||||
// TypeError: (88-89): Only local variables can be assigned to in inline assembly.
|
// DeclarationError: (91-94): Variable not found or variable not lvalue.
|
||||||
|
// DeclarationError: (106-111): Variable not found or variable not lvalue.
|
||||||
|
// TypeError: (123-124): Only local variables can be assigned to in inline assembly.
|
||||||
|
// TypeError: (136-137): Only local variables can be assigned to in inline assembly.
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
constructor() C() public {}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (31-34): Referenced declaration is neither modifier nor base class.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract test {
|
||||||
|
modifier mod() { _; }
|
||||||
|
|
||||||
|
function f() public {
|
||||||
|
mod ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (77-80): Modifier can only be referenced in function headers.
|
Loading…
Reference in New Issue
Block a user