mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #4738 from ethereum/dataloc_merged
Enforce data location.
This commit is contained in:
commit
cc54f6c425
@ -5,7 +5,7 @@ How to update your code:
|
||||
* Change every ``keccak256(a, b, c)`` to ``keccak256(abi.encodePacked(a, b, c))``.
|
||||
* Add ``public`` to every function and ``external`` to every fallback or interface function that does not specify its visibility already.
|
||||
* Make your fallback functions ``external``.
|
||||
* Explicitly state the storage location for local variables of struct and array types, e.g. change ``uint[] x = m_x`` to ``uint[] storage x = m_x``.
|
||||
* Explicitly state the data location for all variables of struct, array or mapping types (including function parameters), e.g. change ``uint[] x = m_x`` to ``uint[] storage x = m_x``. Note that ``external`` functions require parameters with a data location of ``calldata``.
|
||||
* Explicitly convert values of contract type to addresses before using an ``address`` member. Example: if ``c`` is a contract, change ``c.transfer(...)`` to ``address(c).transfer(...)``.
|
||||
|
||||
Breaking Changes:
|
||||
@ -54,6 +54,7 @@ Breaking Changes:
|
||||
* Type Checker: Disallow calling constructor with wrong argument count. This was already the case in the experimental 0.5.0 mode.
|
||||
* Type Checker: Disallow uninitialized storage variables. This was already the case in the experimental 0.5.0 mode.
|
||||
* Type Checker: Detecting cyclic dependencies in variables and structs is limited in recursion to 256.
|
||||
* Type Checker: Require explicit data location for all variables, including function parameters. This was partly already the case in the experimental 0.5.0 mode.
|
||||
* Type Checker: Only accept a single ``bytes`` type for ``.call()`` (and family), ``keccak256()``, ``sha256()`` and ``ripemd160()``.
|
||||
* Type Checker: Fallback function must be external. This was already the case in the experimental 0.5.0 mode.
|
||||
* Type Checker: Interface functions must be declared external. This was already the case in the experimental 0.5.0 mode.
|
||||
@ -61,7 +62,7 @@ Breaking Changes:
|
||||
* Type Checker: Disallow "loose assembly" syntax entirely. This means that jump labels, jumps and non-functional instructions cannot be used anymore.
|
||||
* Type System: Disallow explicit and implicit conversions from decimal literals to ``bytesXX`` types.
|
||||
* Type System: Disallow explicit and implicit conversions from hex literals to ``bytesXX`` types of different size.
|
||||
* Remove obsolete ``std`` directory from the Solidity repository. This means accessing ``https://github.com/ethereum/soldity/blob/develop/std/*.sol`` (or ``https://github.com/ethereum/solidity/std/*.sol`` in Remix) will not be possible.
|
||||
* Remove obsolete ``std`` directory from the Solidity repository. This means accessing ``https://github.com/ethereum/solidity/blob/develop/std/*.sol`` (or ``https://github.com/ethereum/solidity/std/*.sol`` in Remix) will not be possible.
|
||||
* References Resolver: Turn missing storage locations into an error. This was already the case in the experimental 0.5.0 mode.
|
||||
* Syntax Checker: Disallow functions without implementation to use modifiers. This was already the case in the experimental 0.5.0 mode.
|
||||
* Syntax Checker: Named return values in function types are an error.
|
||||
|
@ -90,7 +90,7 @@ of votes.
|
||||
// If the first argument of `require` evaluates
|
||||
// to `false`, execution terminates and all
|
||||
// changes to the state and to Ether balances
|
||||
// are reverted.
|
||||
// are reverted.
|
||||
// This used to consume all gas in old EVM versions, but
|
||||
// not anymore.
|
||||
// It is often a good idea to use `require` to check if
|
||||
@ -708,7 +708,7 @@ For a contract that fulfills payments, the signed message must include:
|
||||
A replay attack is when a signed message is reused to claim authorization for
|
||||
a second action.
|
||||
To avoid replay attacks we will use the same as in Ethereum transactions
|
||||
themselves, a so-called nonce, which is the number of transactions sent by an
|
||||
themselves, a so-called nonce, which is the number of transactions sent by an
|
||||
account.
|
||||
The smart contract will check if a nonce is used multiple times.
|
||||
|
||||
@ -731,7 +731,7 @@ Packing arguments
|
||||
Now that we have identified what information to include in the
|
||||
signed message, we are ready to put the message together, hash it,
|
||||
and sign it. For simplicity, we just concatenate the data.
|
||||
The
|
||||
The
|
||||
`ethereumjs-abi <https://github.com/ethereumjs/ethereumjs-abi>`_ library provides
|
||||
a function called ``soliditySHA3`` that mimics the behavior
|
||||
of Solidity's ``keccak256`` function applied to arguments encoded
|
||||
@ -750,7 +750,7 @@ creates the proper signature for the ``ReceiverPays`` example:
|
||||
["address", "uint256", "uint256", "address"],
|
||||
[recipient, amount, nonce, contractAddress]
|
||||
).toString("hex");
|
||||
|
||||
|
||||
web3.personal.sign(hash, web3.eth.defaultAccount, callback);
|
||||
}
|
||||
|
||||
@ -779,7 +779,7 @@ at the end of this chapter).
|
||||
|
||||
Computing the Message Hash
|
||||
--------------------------
|
||||
|
||||
|
||||
The smart contract needs to know exactly what parameters were signed,
|
||||
and so it must recreate the message from the parameters and use that
|
||||
for signature verification. The functions ``prefixed`` and
|
||||
@ -801,7 +801,7 @@ The full contract
|
||||
|
||||
constructor() public payable {}
|
||||
|
||||
function claimPayment(uint256 amount, uint256 nonce, bytes signature) public {
|
||||
function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) public {
|
||||
require(!usedNonces[nonce]);
|
||||
usedNonces[nonce] = true;
|
||||
|
||||
@ -820,7 +820,7 @@ The full contract
|
||||
}
|
||||
|
||||
/// signature methods.
|
||||
function splitSignature(bytes sig)
|
||||
function splitSignature(bytes memory sig)
|
||||
internal
|
||||
pure
|
||||
returns (uint8 v, bytes32 r, bytes32 s)
|
||||
@ -839,7 +839,7 @@ The full contract
|
||||
return (v, r, s);
|
||||
}
|
||||
|
||||
function recoverSigner(bytes32 message, bytes sig)
|
||||
function recoverSigner(bytes32 message, bytes memory sig)
|
||||
internal
|
||||
pure
|
||||
returns (address)
|
||||
@ -874,7 +874,7 @@ two parties (Alice and Bob). Using it involves three steps:
|
||||
1. Alice funds a smart contract with Ether. This "opens" the payment channel.
|
||||
2. Alice signs messages that specify how much of that Ether is owed to the recipient. This step is repeated for each payment.
|
||||
3. Bob "closes" the payment channel, withdrawing their portion of the Ether and sending the remainder back to the sender.
|
||||
|
||||
|
||||
Not ethat only steps 1 and 3 require Ethereum transactions, step 2 means that
|
||||
the sender transmits a cryptographically signed message to the recipient via off chain ways (e.g. email).
|
||||
This means only two transactions are required to support any number of transfers.
|
||||
@ -906,7 +906,7 @@ Each message includes the following information:
|
||||
|
||||
* The smart contract's address, used to prevent cross-contract replay attacks.
|
||||
* The total amount of Ether that is owed the recipient so far.
|
||||
|
||||
|
||||
A payment channel is closed just once, at the of a series of transfers.
|
||||
Because of this, only one of the messages sent will be redeemed. This is why
|
||||
each message specifies a cumulative total amount of Ether owed, rather than the
|
||||
@ -926,7 +926,7 @@ Here is the modified javascript code to cryptographically sign a message from th
|
||||
[contractAddress, amount]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function signMessage(message, callback) {
|
||||
web3.personal.sign(
|
||||
"0x" + message.toString("hex"),
|
||||
@ -934,10 +934,10 @@ Here is the modified javascript code to cryptographically sign a message from th
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// contractAddress is used to prevent cross-contract replay attacks.
|
||||
// amount, in wei, specifies how much Ether should be sent.
|
||||
|
||||
|
||||
function signPayment(contractAddress, amount, callback) {
|
||||
var message = constructPaymentMessage(contractAddress, amount);
|
||||
signMessage(message, callback);
|
||||
@ -1003,7 +1003,7 @@ The full contract
|
||||
expiration = now + duration;
|
||||
}
|
||||
|
||||
function isValidSignature(uint256 amount, bytes signature)
|
||||
function isValidSignature(uint256 amount, bytes memory signature)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
@ -1017,7 +1017,7 @@ The full contract
|
||||
/// the recipient can close the channel at any time by presenting a
|
||||
/// signed amount from the sender. the recipient will be sent that amount,
|
||||
/// and the remainder will go back to the sender
|
||||
function close(uint256 amount, bytes signature) public {
|
||||
function close(uint256 amount, bytes memory signature) public {
|
||||
require(msg.sender == recipient);
|
||||
require(isValidSignature(amount, signature));
|
||||
|
||||
@ -1043,7 +1043,7 @@ The full contract
|
||||
/// All functions below this are just taken from the chapter
|
||||
/// 'creating and verifying signatures' chapter.
|
||||
|
||||
function splitSignature(bytes sig)
|
||||
function splitSignature(bytes memory sig)
|
||||
internal
|
||||
pure
|
||||
returns (uint8 v, bytes32 r, bytes32 s)
|
||||
@ -1058,11 +1058,11 @@ The full contract
|
||||
// final byte (first byte of the next 32 bytes)
|
||||
v := byte(0, mload(add(sig, 96)))
|
||||
}
|
||||
|
||||
|
||||
return (v, r, s);
|
||||
}
|
||||
|
||||
function recoverSigner(bytes32 message, bytes sig)
|
||||
|
||||
function recoverSigner(bytes32 message, bytes memory sig)
|
||||
internal
|
||||
pure
|
||||
returns (address)
|
||||
@ -1083,7 +1083,7 @@ Note: The function ``splitSignature`` is very simple and does not use all securi
|
||||
A real implementation should use a more rigorously tested library, such as
|
||||
openzepplin's `version <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ECRecovery.sol>`_ of this code.
|
||||
|
||||
|
||||
|
||||
|
||||
Verifying Payments
|
||||
------------------
|
||||
@ -1101,7 +1101,7 @@ The recipient should verify each message using the following process:
|
||||
2. Verify that the new total is the expected amount.
|
||||
3. Verify that the new total does not exceed the amount of Ether escrowed.
|
||||
4. Verify that the signature is valid and comes from the payment channel sender.
|
||||
|
||||
|
||||
We'll use the `ethereumjs-util <https://github.com/ethereumjs/ethereumjs-util>`_
|
||||
library to write this verifications. The final step can be done a number of ways,
|
||||
but if it's being done in **JavaScript**.
|
||||
@ -1117,14 +1117,14 @@ above:
|
||||
["\x19Ethereum Signed Message:\n32", hash]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function recoverSigner(message, signature) {
|
||||
var split = ethereumjs.Util.fromRpcSig(signature);
|
||||
var publicKey = ethereumjs.Util.ecrecover(message, split.v, split.r, split.s);
|
||||
var signer = ethereumjs.Util.pubToAddress(publicKey).toString("hex");
|
||||
return signer;
|
||||
}
|
||||
|
||||
|
||||
function isValidSignature(contractAddress, amount, signature, expectedSigner) {
|
||||
var message = prefixed(constructPaymentMessage(contractAddress, amount));
|
||||
var signer = recoverSigner(message, signature);
|
||||
|
@ -580,16 +580,18 @@ variables are held).
|
||||
Data location
|
||||
-------------
|
||||
|
||||
Every complex type, i.e. *arrays* and *structs*, has an additional
|
||||
annotation, the "data location", about whether it is stored in memory or in storage. Depending on the
|
||||
context, there is always a default, but it can be overridden by appending
|
||||
either ``storage`` or ``memory`` to the type. The default for function parameters (including return parameters) is ``memory``, the default for local variables is ``storage`` and the location is forced
|
||||
to ``storage`` for state variables (obviously).
|
||||
|
||||
There is also a third data location, ``calldata``, which is a non-modifiable,
|
||||
non-persistent area where function arguments are stored. Function parameters
|
||||
(not return parameters) of external functions are forced to ``calldata`` and
|
||||
behave mostly like ``memory``.
|
||||
Every complex 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,
|
||||
non-persistent area where function arguments are stored, and behaves mostly like memory.
|
||||
|
||||
|
||||
.. note::
|
||||
Prior to version 0.5.0 the data location could be omitted, and would default to different locations
|
||||
depending on the kind of variable, function type, etc., but all complex types must now give an explicit
|
||||
data location.
|
||||
|
||||
Data locations are important because they change how assignments behave:
|
||||
assignments between storage and memory and also to a state variable (even from other state variables)
|
||||
@ -635,10 +637,6 @@ Forced data location:
|
||||
- parameters (not return) of external functions: calldata
|
||||
- state variables: storage
|
||||
|
||||
Default data location:
|
||||
- parameters (also return) of functions: memory
|
||||
- all other local variables: storage
|
||||
|
||||
.. index:: ! array
|
||||
|
||||
.. _arrays:
|
||||
|
@ -49,27 +49,23 @@ std::string joinHumanReadable
|
||||
std::string const& _lastSeparator = ""
|
||||
)
|
||||
{
|
||||
auto it = begin(_list);
|
||||
auto itEnd = end(_list);
|
||||
auto const itEnd = end(_list);
|
||||
|
||||
std::string result;
|
||||
|
||||
// append first string
|
||||
if (it != itEnd)
|
||||
for (auto it = begin(_list); it != itEnd; )
|
||||
{
|
||||
result += *it;
|
||||
std::string element = *it;
|
||||
bool first = (it == begin(_list));
|
||||
++it;
|
||||
}
|
||||
|
||||
for (;it != itEnd; ++it)
|
||||
{
|
||||
if ((std::next(it) == itEnd) && !_lastSeparator.empty())
|
||||
result += _lastSeparator; // last iteration
|
||||
else
|
||||
result += _separator;
|
||||
|
||||
// append string
|
||||
result += *it;
|
||||
if (!first)
|
||||
{
|
||||
if (it == itEnd && !_lastSeparator.empty())
|
||||
result += _lastSeparator; // last iteration
|
||||
else
|
||||
result += _separator;
|
||||
}
|
||||
result += std::move(element);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -626,6 +626,17 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&)
|
||||
closeCurrentScope();
|
||||
}
|
||||
|
||||
bool DeclarationRegistrationHelper::visit(FunctionTypeName& _funTypeName)
|
||||
{
|
||||
enterNewSubScope(_funTypeName);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeclarationRegistrationHelper::endVisit(FunctionTypeName&)
|
||||
{
|
||||
closeCurrentScope();
|
||||
}
|
||||
|
||||
bool DeclarationRegistrationHelper::visit(Block& _block)
|
||||
{
|
||||
_block.setScope(m_currentScope);
|
||||
|
@ -171,6 +171,8 @@ private:
|
||||
void endVisit(FunctionDefinition& _function) override;
|
||||
bool visit(ModifierDefinition& _modifier) override;
|
||||
void endVisit(ModifierDefinition& _modifier) override;
|
||||
bool visit(FunctionTypeName& _funTypeName) override;
|
||||
void endVisit(FunctionTypeName& _funTypeName) override;
|
||||
bool visit(Block& _block) override;
|
||||
void endVisit(Block& _block) override;
|
||||
bool visit(ForStatement& _forLoop) override;
|
||||
|
@ -30,7 +30,10 @@
|
||||
#include <libsolidity/inlineasm/AsmData.h>
|
||||
#include <libsolidity/interface/ErrorReporter.h>
|
||||
|
||||
#include <libdevcore/StringUtils.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
@ -155,7 +158,10 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
||||
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||
_typeName.annotation().type = make_shared<ContractType>(*contract);
|
||||
else
|
||||
{
|
||||
_typeName.annotation().type = make_shared<TupleType>();
|
||||
typeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
||||
}
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
||||
@ -166,13 +172,13 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
||||
case VariableDeclaration::Visibility::External:
|
||||
break;
|
||||
default:
|
||||
typeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\".");
|
||||
fatalTypeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\".");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_typeName.isPayable() && _typeName.visibility() != VariableDeclaration::Visibility::External)
|
||||
{
|
||||
typeError(_typeName.location(), "Only external function types can be payable.");
|
||||
fatalTypeError(_typeName.location(), "Only external function types can be payable.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -182,7 +188,7 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
||||
solAssert(t->annotation().type, "Type not set for parameter.");
|
||||
if (!t->annotation().type->canBeUsedExternally(false))
|
||||
{
|
||||
typeError(t->location(), "Internal type cannot be used for external function type.");
|
||||
fatalTypeError(t->location(), "Internal type cannot be used for external function type.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -300,6 +306,9 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
if (_variable.annotation().type)
|
||||
return;
|
||||
|
||||
if (_variable.isConstant() && !_variable.isStateVariable())
|
||||
m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables.");
|
||||
|
||||
if (!_variable.typeName())
|
||||
{
|
||||
// This can still happen in very unusual cases where a developer uses constructs, such as
|
||||
@ -309,127 +318,92 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
// after this step.
|
||||
return;
|
||||
}
|
||||
|
||||
TypePointer type;
|
||||
type = _variable.typeName()->annotation().type;
|
||||
using Location = VariableDeclaration::Location;
|
||||
Location varLoc = _variable.referenceLocation();
|
||||
DataLocation typeLoc = DataLocation::Memory;
|
||||
// References are forced to calldata for external function parameters (not return)
|
||||
// and memory for parameters (also return) of publicly visible functions.
|
||||
// They default to memory for function parameters and storage for local variables.
|
||||
// As an exception, "storage" is allowed for library functions.
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
|
||||
|
||||
set<Location> allowedDataLocations = _variable.allowedDataLocations();
|
||||
if (!allowedDataLocations.count(varLoc))
|
||||
{
|
||||
bool isPointer = true;
|
||||
if (_variable.isExternalCallableParameter())
|
||||
auto locationToString = [](VariableDeclaration::Location _location) -> string
|
||||
{
|
||||
auto const& contract = dynamic_cast<ContractDefinition const&>(
|
||||
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
|
||||
);
|
||||
if (contract.isLibrary())
|
||||
switch (_location)
|
||||
{
|
||||
if (varLoc == Location::Memory)
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location has to be calldata or storage for external "
|
||||
"library functions (remove the \"memory\" keyword)."
|
||||
);
|
||||
case Location::Memory: return "\"memory\"";
|
||||
case Location::Storage: return "\"storage\"";
|
||||
case Location::CallData: return "\"calldata\"";
|
||||
case Location::Default: return "none";
|
||||
}
|
||||
else
|
||||
{
|
||||
// force location of external function parameters (not return) to calldata
|
||||
if (varLoc != Location::CallData && varLoc != Location::Default)
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location has to be calldata for external functions "
|
||||
"(remove the \"memory\" or \"storage\" keyword)."
|
||||
);
|
||||
}
|
||||
if (varLoc == Location::Default || varLoc == Location::CallData)
|
||||
typeLoc = DataLocation::CallData;
|
||||
else
|
||||
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
|
||||
}
|
||||
else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
|
||||
{
|
||||
auto const& contract = dynamic_cast<ContractDefinition const&>(
|
||||
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
|
||||
);
|
||||
// force locations of public or external function (return) parameters to memory
|
||||
if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary())
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location has to be memory for publicly visible functions "
|
||||
"(remove the \"storage\" or \"calldata\" keyword)."
|
||||
);
|
||||
if (varLoc == Location::Default || !contract.isLibrary())
|
||||
typeLoc = DataLocation::Memory;
|
||||
else
|
||||
{
|
||||
if (varLoc == Location::CallData)
|
||||
fatalTypeError(_variable.location(),
|
||||
"Location cannot be calldata for non-external functions "
|
||||
"(remove the \"calldata\" keyword)."
|
||||
);
|
||||
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
string errorString;
|
||||
if (!_variable.hasReferenceOrMappingType())
|
||||
errorString = "Data location can only be specified for array, struct or mapping types";
|
||||
else
|
||||
{
|
||||
if (_variable.isConstant())
|
||||
{
|
||||
if (varLoc != Location::Default && varLoc != Location::Memory)
|
||||
fatalTypeError(
|
||||
_variable.location(),
|
||||
"Data location has to be \"memory\" (or unspecified) for constants."
|
||||
);
|
||||
typeLoc = DataLocation::Memory;
|
||||
}
|
||||
else if (varLoc == Location::Default)
|
||||
{
|
||||
if (_variable.isCallableParameter())
|
||||
typeLoc = DataLocation::Memory;
|
||||
else
|
||||
{
|
||||
typeLoc = DataLocation::Storage;
|
||||
if (_variable.isLocalVariable())
|
||||
typeError(
|
||||
_variable.location(),
|
||||
"Data location must be specified as either \"memory\" or \"storage\"."
|
||||
);
|
||||
}
|
||||
}
|
||||
errorString = "Data location must be " +
|
||||
joinHumanReadable(
|
||||
allowedDataLocations | boost::adaptors::transformed(locationToString),
|
||||
", ",
|
||||
" or "
|
||||
);
|
||||
if (_variable.isCallableParameter())
|
||||
errorString +=
|
||||
" for " +
|
||||
string(_variable.isReturnParameter() ? "return " : "") +
|
||||
"parameter in" +
|
||||
string(_variable.isExternalCallableParameter() ? " external" : "") +
|
||||
" function";
|
||||
else
|
||||
{
|
||||
switch (varLoc)
|
||||
{
|
||||
case Location::Memory:
|
||||
typeLoc = DataLocation::Memory;
|
||||
break;
|
||||
case Location::Storage:
|
||||
typeLoc = DataLocation::Storage;
|
||||
break;
|
||||
case Location::CallData:
|
||||
fatalTypeError(_variable.location(),
|
||||
"Variable cannot be declared as \"calldata\" (remove the \"calldata\" keyword)."
|
||||
);
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Unknown data location");
|
||||
}
|
||||
}
|
||||
isPointer = !_variable.isStateVariable();
|
||||
errorString += " for variable";
|
||||
}
|
||||
errorString += ", but " + locationToString(varLoc) + " was given.";
|
||||
typeError(_variable.location(), errorString);
|
||||
|
||||
solAssert(!allowedDataLocations.empty(), "");
|
||||
varLoc = *allowedDataLocations.begin();
|
||||
}
|
||||
|
||||
// Find correct data location.
|
||||
if (_variable.isEventParameter())
|
||||
{
|
||||
solAssert(varLoc == Location::Default, "");
|
||||
typeLoc = DataLocation::Memory;
|
||||
}
|
||||
else if (_variable.isStateVariable())
|
||||
{
|
||||
solAssert(varLoc == Location::Default, "");
|
||||
typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage;
|
||||
}
|
||||
else if (
|
||||
dynamic_cast<StructDefinition const*>(_variable.scope()) ||
|
||||
dynamic_cast<EnumDefinition const*>(_variable.scope())
|
||||
)
|
||||
// The actual location will later be changed depending on how the type is used.
|
||||
typeLoc = DataLocation::Storage;
|
||||
else
|
||||
switch (varLoc)
|
||||
{
|
||||
case Location::Memory:
|
||||
typeLoc = DataLocation::Memory;
|
||||
break;
|
||||
case Location::Storage:
|
||||
typeLoc = DataLocation::Storage;
|
||||
break;
|
||||
case Location::CallData:
|
||||
typeLoc = DataLocation::CallData;
|
||||
break;
|
||||
case Location::Default:
|
||||
solAssert(!_variable.hasReferenceOrMappingType(), "Data location not properly set.");
|
||||
}
|
||||
|
||||
TypePointer type = _variable.typeName()->annotation().type;
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
|
||||
{
|
||||
bool isPointer = !_variable.isStateVariable();
|
||||
type = ref->copyForLocation(typeLoc, isPointer);
|
||||
}
|
||||
else if (dynamic_cast<MappingType const*>(type.get()))
|
||||
{
|
||||
if (_variable.isLocalVariable() && varLoc != Location::Storage)
|
||||
typeError(
|
||||
_variable.location(),
|
||||
"Data location for mappings must be specified as \"storage\"."
|
||||
);
|
||||
}
|
||||
else if (varLoc != Location::Default && !ref)
|
||||
typeError(_variable.location(), "Data location can only be given for array or struct types.");
|
||||
|
||||
_variable.annotation().type = type;
|
||||
}
|
||||
|
@ -630,8 +630,13 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
|
||||
{
|
||||
if (
|
||||
type(*var)->category() == Type::Category::Mapping &&
|
||||
!type(*var)->dataStoredIn(DataLocation::Storage)
|
||||
)
|
||||
m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\".");
|
||||
else if (
|
||||
!type(*var)->canLiveOutsideStorage() &&
|
||||
!(_function.visibility() <= FunctionDefinition::Visibility::Internal)
|
||||
_function.visibility() > FunctionDefinition::Visibility::Internal
|
||||
)
|
||||
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
||||
if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction)))
|
||||
@ -716,8 +721,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
expectType(*_variable.value(), *varType);
|
||||
if (_variable.isConstant())
|
||||
{
|
||||
if (!_variable.isStateVariable())
|
||||
m_errorReporter.typeError(_variable.location(), "Illegal use of \"constant\" specifier.");
|
||||
if (!_variable.type()->isValueType())
|
||||
{
|
||||
bool allowed = false;
|
||||
|
@ -418,6 +418,7 @@ bool VariableDeclaration::isLocalVariable() const
|
||||
{
|
||||
auto s = scope();
|
||||
return
|
||||
dynamic_cast<FunctionTypeName const*>(s) ||
|
||||
dynamic_cast<CallableDeclaration const*>(s) ||
|
||||
dynamic_cast<Block const*>(s) ||
|
||||
dynamic_cast<ForStatement const*>(s);
|
||||
@ -425,14 +426,18 @@ bool VariableDeclaration::isLocalVariable() const
|
||||
|
||||
bool VariableDeclaration::isCallableParameter() const
|
||||
{
|
||||
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
|
||||
if (!callable)
|
||||
return false;
|
||||
for (auto const& variable: callable->parameters())
|
||||
if (variable.get() == this)
|
||||
return true;
|
||||
if (callable->returnParameterList())
|
||||
for (auto const& variable: callable->returnParameterList()->parameters())
|
||||
if (isReturnParameter())
|
||||
return true;
|
||||
|
||||
vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
|
||||
|
||||
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
|
||||
parameters = &funTypeName->parameterTypes();
|
||||
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
|
||||
parameters = &callable->parameters();
|
||||
|
||||
if (parameters)
|
||||
for (auto const& variable: *parameters)
|
||||
if (variable.get() == this)
|
||||
return true;
|
||||
return false;
|
||||
@ -445,11 +450,16 @@ bool VariableDeclaration::isLocalOrReturn() const
|
||||
|
||||
bool VariableDeclaration::isReturnParameter() const
|
||||
{
|
||||
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
|
||||
if (!callable)
|
||||
return false;
|
||||
if (callable->returnParameterList())
|
||||
for (auto const& variable: callable->returnParameterList()->parameters())
|
||||
vector<ASTPointer<VariableDeclaration>> const* returnParameters = nullptr;
|
||||
|
||||
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
|
||||
returnParameters = &funTypeName->returnParameterTypes();
|
||||
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
|
||||
if (callable->returnParameterList())
|
||||
returnParameters = &callable->returnParameterList()->parameters();
|
||||
|
||||
if (returnParameters)
|
||||
for (auto const& variable: *returnParameters)
|
||||
if (variable.get() == this)
|
||||
return true;
|
||||
return false;
|
||||
@ -457,15 +467,88 @@ bool VariableDeclaration::isReturnParameter() const
|
||||
|
||||
bool VariableDeclaration::isExternalCallableParameter() const
|
||||
{
|
||||
auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
|
||||
if (!callable || callable->visibility() != Declaration::Visibility::External)
|
||||
if (!isCallableParameter())
|
||||
return false;
|
||||
for (auto const& variable: callable->parameters())
|
||||
if (variable.get() == this)
|
||||
return true;
|
||||
|
||||
if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
|
||||
if (callable->visibility() == Declaration::Visibility::External)
|
||||
return !isReturnParameter();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VariableDeclaration::isInternalCallableParameter() const
|
||||
{
|
||||
if (!isCallableParameter())
|
||||
return false;
|
||||
|
||||
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
|
||||
return funTypeName->visibility() == Declaration::Visibility::Internal;
|
||||
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
|
||||
return callable->visibility() <= Declaration::Visibility::Internal;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VariableDeclaration::isLibraryFunctionParameter() const
|
||||
{
|
||||
if (!isCallableParameter())
|
||||
return false;
|
||||
if (auto const* funDef = dynamic_cast<FunctionDefinition const*>(scope()))
|
||||
return dynamic_cast<ContractDefinition const&>(*funDef->scope()).isLibrary();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VariableDeclaration::isEventParameter() const
|
||||
{
|
||||
return dynamic_cast<EventDefinition const*>(scope()) != nullptr;
|
||||
}
|
||||
|
||||
bool VariableDeclaration::hasReferenceOrMappingType() const
|
||||
{
|
||||
solAssert(typeName(), "");
|
||||
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
|
||||
TypePointer const& type = typeName()->annotation().type;
|
||||
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type.get());
|
||||
}
|
||||
|
||||
set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
|
||||
{
|
||||
using Location = VariableDeclaration::Location;
|
||||
|
||||
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
|
||||
return set<Location>{ Location::Default };
|
||||
else if (isStateVariable() && isConstant())
|
||||
return set<Location>{ Location::Memory };
|
||||
else if (isExternalCallableParameter())
|
||||
{
|
||||
set<Location> locations{ Location::CallData };
|
||||
if (isLibraryFunctionParameter())
|
||||
locations.insert(Location::Storage);
|
||||
return locations;
|
||||
}
|
||||
else if (isCallableParameter())
|
||||
{
|
||||
set<Location> locations{ Location::Memory };
|
||||
if (isInternalCallableParameter() || isLibraryFunctionParameter())
|
||||
locations.insert(Location::Storage);
|
||||
return locations;
|
||||
}
|
||||
else if (isLocalVariable())
|
||||
{
|
||||
solAssert(typeName(), "");
|
||||
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
|
||||
if (typeName()->annotation().type->category() == Type::Category::Mapping)
|
||||
return set<Location>{ Location::Storage };
|
||||
else
|
||||
// TODO: add Location::Calldata once implemented for local variables.
|
||||
return set<Location>{ Location::Memory, Location::Storage };
|
||||
}
|
||||
else
|
||||
// Struct members etc.
|
||||
return set<Location>{ Location::Default };
|
||||
}
|
||||
|
||||
TypePointer VariableDeclaration::type() const
|
||||
{
|
||||
return annotation().type;
|
||||
@ -580,7 +663,7 @@ bool Literal::passesAddressChecksum() const
|
||||
return dev::passesAddressChecksum(value(), true);
|
||||
}
|
||||
|
||||
std::string Literal::getChecksummedAddress() const
|
||||
string Literal::getChecksummedAddress() const
|
||||
{
|
||||
solAssert(isHexNumber(), "Expected hex number");
|
||||
/// Pad literal to be a proper hex address.
|
||||
|
@ -685,6 +685,8 @@ public:
|
||||
virtual bool isLValue() const override;
|
||||
virtual bool isPartOfExternalInterface() const override { return isPublic(); }
|
||||
|
||||
/// @returns true iff this variable is the parameter (or return parameter) of a function
|
||||
/// (or function type name or event) or declared inside a function body.
|
||||
bool isLocalVariable() const;
|
||||
/// @returns true if this variable is a parameter or return parameter of a function.
|
||||
bool isCallableParameter() const;
|
||||
@ -693,13 +695,27 @@ public:
|
||||
/// @returns true if this variable is a local variable or return parameter.
|
||||
bool isLocalOrReturn() const;
|
||||
/// @returns true if this variable is a parameter (not return parameter) of an external function.
|
||||
/// This excludes parameters of external function type names.
|
||||
bool isExternalCallableParameter() const;
|
||||
/// @returns true if this variable is a parameter or return parameter of an internal function
|
||||
/// or a function type of internal visibility.
|
||||
bool isInternalCallableParameter() const;
|
||||
/// @returns true iff this variable is a parameter(or return parameter of a library function
|
||||
bool isLibraryFunctionParameter() const;
|
||||
/// @returns true if the type of the variable does not need to be specified, i.e. it is declared
|
||||
/// in the body of a function or modifier.
|
||||
/// @returns true if this variable is a parameter of an event.
|
||||
bool isEventParameter() const;
|
||||
/// @returns true if the type of the variable is a reference or mapping type, i.e.
|
||||
/// array, struct or mapping. These types can take a data location (and often require it).
|
||||
/// Can only be called after reference resolution.
|
||||
bool hasReferenceOrMappingType() const;
|
||||
bool isStateVariable() const { return m_isStateVariable; }
|
||||
bool isIndexed() const { return m_isIndexed; }
|
||||
bool isConstant() const { return m_isConstant; }
|
||||
Location referenceLocation() const { return m_location; }
|
||||
/// @returns a set of allowed storage locations for the variable.
|
||||
std::set<Location> allowedDataLocations() const;
|
||||
|
||||
virtual TypePointer type() const override;
|
||||
|
||||
|
@ -140,7 +140,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
}
|
||||
return (true, false, 0);
|
||||
}
|
||||
function replaceModule(string name, address addr, bool callCallback) external returns (bool success) {
|
||||
function replaceModule(string calldata name, address addr, bool callCallback) external returns (bool success) {
|
||||
/*
|
||||
Module replace, can be called only by the Publisher contract.
|
||||
|
||||
@ -167,7 +167,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
return true;
|
||||
}
|
||||
|
||||
function callReplaceCallback(string moduleName, address newModule) external returns (bool success) {
|
||||
function callReplaceCallback(string calldata moduleName, address newModule) external returns (bool success) {
|
||||
require( block.number < debugModeUntil );
|
||||
if ( ! insertAndCheckDo(calcDoHash("callReplaceCallback", keccak256(abi.encodePacked(moduleName, newModule)))) ) {
|
||||
return true;
|
||||
@ -178,7 +178,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
return true;
|
||||
}
|
||||
|
||||
function newModule(string name, address addr, bool schellingEvent, bool transferEvent) external returns (bool success) {
|
||||
function newModule(string calldata name, address addr, bool schellingEvent, bool transferEvent) external returns (bool success) {
|
||||
/*
|
||||
Adding new module to the database. Can be called only by the Publisher contract.
|
||||
|
||||
@ -199,7 +199,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
addModule( modules_s(addr, keccak256(bytes(name)), schellingEvent, transferEvent), true);
|
||||
return true;
|
||||
}
|
||||
function dropModule(string name, bool callCallback) external returns (bool success) {
|
||||
function dropModule(string calldata name, bool callCallback) external returns (bool success) {
|
||||
/*
|
||||
Deleting module from the database. Can be called only by the Publisher contract.
|
||||
|
||||
@ -224,7 +224,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
return true;
|
||||
}
|
||||
|
||||
function callDisableCallback(string moduleName) external returns (bool success) {
|
||||
function callDisableCallback(string calldata moduleName) external returns (bool success) {
|
||||
require( block.number < debugModeUntil );
|
||||
if ( ! insertAndCheckDo(calcDoHash("callDisableCallback", keccak256(bytes(moduleName)))) ) {
|
||||
return true;
|
||||
@ -406,7 +406,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
require( token(modules[_id].addr).burn(from, value) );
|
||||
return true;
|
||||
}
|
||||
function configureModule(string moduleName, announcementType aType, uint256 value) external returns (bool success) {
|
||||
function configureModule(string calldata moduleName, announcementType aType, uint256 value) external returns (bool success) {
|
||||
/*
|
||||
Changing configuration of a module. Can be called only by Publisher or while debug mode by owners.
|
||||
|
||||
|
@ -5,8 +5,8 @@ import "./tokenDB.sol";
|
||||
import "./module.sol";
|
||||
|
||||
contract thirdPartyPContractAbstract {
|
||||
function receiveCorionPremiumToken(address, uint256, bytes) external returns (bool, uint256) {}
|
||||
function approvedCorionPremiumToken(address, uint256, bytes) external returns (bool) {}
|
||||
function receiveCorionPremiumToken(address, uint256, bytes calldata) external returns (bool, uint256) {}
|
||||
function approvedCorionPremiumToken(address, uint256, bytes calldata) external returns (bool) {}
|
||||
}
|
||||
|
||||
contract ptokenDB is tokenDB {}
|
||||
@ -108,7 +108,7 @@ contract premium is module, safeMath {
|
||||
* @param extraData Data to give forward to the receiver
|
||||
* @return True if the approval was successful
|
||||
*/
|
||||
function approveAndCall(address spender, uint256 amount, uint256 nonce, bytes extraData) isReady external returns (bool success) {
|
||||
function approveAndCall(address spender, uint256 amount, uint256 nonce, bytes calldata extraData) isReady external returns (bool success) {
|
||||
/*
|
||||
Authorize another address to use an exact amount of the principal’s balance.
|
||||
After the transaction the approvedCorionPremiumToken function of the address will be called with the given data.
|
||||
@ -226,7 +226,7 @@ contract premium is module, safeMath {
|
||||
* @param extraData Data to give forward to the receiver
|
||||
* @return Whether the transfer was successful or not
|
||||
*/
|
||||
function transfer(address to, uint256 amount, bytes extraData) isReady external returns (bool success) {
|
||||
function transfer(address to, uint256 amount, bytes calldata extraData) isReady external returns (bool success) {
|
||||
/*
|
||||
Launch a transaction where we transfer from a given address to another one.
|
||||
After thetransaction the approvedCorionPremiumToken function of the receiver’s address is going to be called with the given data.
|
||||
|
@ -213,7 +213,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
return ( ! priv && ( rate >= publicMinRate && rate <= publicMaxRate ) ) ||
|
||||
( priv && ( rate >= privateMinRate && rate <= privateMaxRate ) );
|
||||
}
|
||||
function createProvider(bool priv, string name, string website, string country, string info, uint8 rate, bool isForRent, address admin) isReady external {
|
||||
function createProvider(bool priv, string calldata name, string calldata website, string calldata country, string calldata info, uint8 rate, bool isForRent, address admin) isReady external {
|
||||
/*
|
||||
Creating a provider.
|
||||
During the ICO its not allowed to create provider.
|
||||
@ -270,7 +270,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
}
|
||||
emit EProviderOpen(msg.sender, currHeight);
|
||||
}
|
||||
function setProviderDetails(address addr, string website, string country, string info, uint8 rate, address admin) isReady external {
|
||||
function setProviderDetails(address addr, string calldata website, string calldata country, string calldata info, uint8 rate, address admin) isReady external {
|
||||
/*
|
||||
Modifying the datas of the provider.
|
||||
This can only be invited by the provider’s admin.
|
||||
@ -369,7 +369,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
setRightForInterest(getProviderCurrentSupply(msg.sender), 0, providers[msg.sender].data[currHeight].priv);
|
||||
emit EProviderClose(msg.sender, currHeight);
|
||||
}
|
||||
function allowUsers(address provider, address[] addr) isReady external {
|
||||
function allowUsers(address provider, address[] calldata addr) isReady external {
|
||||
/*
|
||||
Permition of the user to be able to connect to the provider.
|
||||
This can only be invited by the provider’s admin.
|
||||
@ -387,7 +387,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
providers[provider].data[currHeight].allowedUsers[addr[a]] = true;
|
||||
}
|
||||
}
|
||||
function disallowUsers(address provider, address[] addr) isReady external {
|
||||
function disallowUsers(address provider, address[] calldata addr) isReady external {
|
||||
/*
|
||||
Disable of the user not to be able to connect to the provider.
|
||||
It is can called only for the admin of the provider.
|
||||
|
@ -116,7 +116,7 @@ contract publisher is announcementTypes, module, safeMath {
|
||||
return _amount * oppositeRate / 100 > weight;
|
||||
}
|
||||
|
||||
function newAnnouncement(announcementType Type, string Announcement, string Link, bool Oppositable, string _str, uint256 _uint, address _addr) onlyOwner external {
|
||||
function newAnnouncement(announcementType Type, string calldata Announcement, string calldata Link, bool Oppositable, string calldata _str, uint256 _uint, address _addr) onlyOwner external {
|
||||
/*
|
||||
New announcement. Can be called only by those in the admin list
|
||||
|
||||
|
@ -310,7 +310,7 @@ contract schelling is module, announcementTypes, schellingVars {
|
||||
|
||||
setRound(currentRound, round);
|
||||
}
|
||||
function sendVote(string vote) isReady noContract external {
|
||||
function sendVote(string calldata vote) isReady noContract external {
|
||||
/*
|
||||
Check vote (Envelope opening)
|
||||
Only the sent “envelopes” can be opened.
|
||||
|
@ -7,8 +7,8 @@ import "./moduleHandler.sol";
|
||||
import "./tokenDB.sol";
|
||||
|
||||
contract thirdPartyContractAbstract {
|
||||
function receiveCorionToken(address, uint256, bytes) external returns (bool, uint256) {}
|
||||
function approvedCorionToken(address, uint256, bytes) external returns (bool) {}
|
||||
function receiveCorionToken(address, uint256, bytes calldata) external returns (bool, uint256) {}
|
||||
function approvedCorionToken(address, uint256, bytes calldata) external returns (bool) {}
|
||||
}
|
||||
|
||||
contract token is safeMath, module, announcementTypes {
|
||||
@ -123,7 +123,7 @@ contract token is safeMath, module, announcementTypes {
|
||||
* @param extraData Data to give forward to the receiver
|
||||
* @return True if the approval was successful
|
||||
*/
|
||||
function approveAndCall(address spender, uint256 amount, uint256 nonce, bytes extraData) isReady external returns (bool success) {
|
||||
function approveAndCall(address spender, uint256 amount, uint256 nonce, bytes calldata extraData) isReady external returns (bool success) {
|
||||
/*
|
||||
Authorise another address to use a certain quantity of the authorising owner’s balance
|
||||
Following the transaction the receiver address `approvedCorionToken` function is called by the given data
|
||||
@ -267,7 +267,7 @@ contract token is safeMath, module, announcementTypes {
|
||||
* @param extraData Data to give forward to the receiver
|
||||
* @return Whether the transfer was successful or not
|
||||
*/
|
||||
function transfer(address to, uint256 amount, bytes extraData) isReady external returns (bool success) {
|
||||
function transfer(address to, uint256 amount, bytes calldata extraData) isReady external returns (bool success) {
|
||||
/*
|
||||
Start transaction to send a quantity from a given address to another address
|
||||
After transaction the function `receiveCorionToken`of the receiver is called by the given data
|
||||
|
@ -55,7 +55,7 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
|
||||
* @param _value The value to send
|
||||
* @param _data The data part of the transaction
|
||||
*/
|
||||
function execute(address _to, uint256 _value, bytes _data) external onlyOwner returns (bytes32 _r) {
|
||||
function execute(address _to, uint256 _value, bytes calldata _data) external onlyOwner returns (bytes32 _r) {
|
||||
// first, take the opportunity to check that we're under the daily limit.
|
||||
if (underLimit(_value)) {
|
||||
emit SingleTransact(msg.sender, _value, _to, _data);
|
||||
|
@ -18,7 +18,7 @@ contract HasNoTokens is Ownable {
|
||||
* @param value_ uint256 the amount of the specified token
|
||||
* @param data_ Bytes The data passed from the caller.
|
||||
*/
|
||||
function tokenFallback(address from_, uint256 value_, bytes data_) external {
|
||||
function tokenFallback(address from_, uint256 value_, bytes calldata data_) external {
|
||||
revert();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,6 @@ contract Multisig {
|
||||
|
||||
// TODO: document
|
||||
function changeOwner(address _from, address _to) external;
|
||||
function execute(address _to, uint256 _value, bytes _data) external returns (bytes32);
|
||||
function execute(address _to, uint256 _value, bytes calldata _data) external returns (bytes32);
|
||||
function confirm(bytes32 _h) public returns (bool);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ contract GlobalRegistrar is Registrar, AuctionSystem {
|
||||
}
|
||||
}
|
||||
|
||||
function reserve(string _name) external payable {
|
||||
function reserve(string calldata _name) external payable {
|
||||
if (bytes(_name).length == 0)
|
||||
revert();
|
||||
bool needAuction = requiresAuction(_name);
|
||||
|
@ -348,7 +348,7 @@ contract multisig {
|
||||
|
||||
// TODO: document
|
||||
function changeOwner(address _from, address _to) external;
|
||||
function execute(address _to, uint _value, bytes _data) external returns (bytes32);
|
||||
function execute(address _to, uint _value, bytes calldata _data) external returns (bytes32);
|
||||
function confirm(bytes32 _h) public returns (bool);
|
||||
}
|
||||
|
||||
@ -390,7 +390,7 @@ contract Wallet is multisig, multiowned, daylimit {
|
||||
// If not, goes into multisig process. We provide a hash on return to allow the sender to provide
|
||||
// shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value
|
||||
// and _data arguments). They still get the option of using them if they want, anyways.
|
||||
function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) {
|
||||
function execute(address _to, uint _value, bytes calldata _data) external onlyowner returns (bytes32 _r) {
|
||||
// first, take the opportunity to check that we're under the daily limit.
|
||||
if (underLimit(_value)) {
|
||||
emit SingleTransact(msg.sender, _value, _to, _data);
|
||||
|
@ -234,7 +234,7 @@ BOOST_AUTO_TEST_CASE(byte_arrays)
|
||||
return (a, b.length, b[3], c);
|
||||
}
|
||||
|
||||
function f_external(uint a, bytes b, uint c)
|
||||
function f_external(uint a, bytes calldata b, uint c)
|
||||
external pure returns (uint, uint, byte, uint) {
|
||||
return (a, b.length, b[3], c);
|
||||
}
|
||||
@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(calldata_arrays_too_large)
|
||||
{
|
||||
string sourceCode = R"(
|
||||
contract C {
|
||||
function f(uint a, uint[] b, uint c) external pure returns (uint) {
|
||||
function f(uint a, uint[] calldata b, uint c) external pure returns (uint) {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ BOOST_AUTO_TEST_CASE(calldata)
|
||||
string sourceCode = R"(
|
||||
contract C {
|
||||
event E(bytes);
|
||||
function f(bytes a) external {
|
||||
function f(bytes calldata a) external {
|
||||
emit E(a);
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@
|
||||
"id" : 3,
|
||||
"name" : "",
|
||||
"nodeType" : "VariableDeclaration",
|
||||
"scope" : 16,
|
||||
"scope" : 5,
|
||||
"src" : "61:4:1",
|
||||
"stateVariable" : false,
|
||||
"storageLocation" : "default",
|
||||
@ -167,7 +167,7 @@
|
||||
"id" : 10,
|
||||
"name" : "",
|
||||
"nodeType" : "VariableDeclaration",
|
||||
"scope" : 16,
|
||||
"scope" : 12,
|
||||
"src" : "113:4:1",
|
||||
"stateVariable" : false,
|
||||
"storageLocation" : "default",
|
||||
|
@ -1 +1,3 @@
|
||||
contract C { function f(function() external payable returns (uint) x) returns (function() external view returns (uint)) {} }
|
||||
|
||||
// ----
|
||||
|
@ -100,7 +100,7 @@
|
||||
{
|
||||
"constant" : false,
|
||||
"name" : "",
|
||||
"scope" : 16,
|
||||
"scope" : 5,
|
||||
"stateVariable" : false,
|
||||
"storageLocation" : "default",
|
||||
"type" : "uint256",
|
||||
@ -191,7 +191,7 @@
|
||||
{
|
||||
"constant" : false,
|
||||
"name" : "",
|
||||
"scope" : 16,
|
||||
"scope" : 12,
|
||||
"stateVariable" : false,
|
||||
"storageLocation" : "default",
|
||||
"type" : "uint256",
|
||||
|
@ -727,7 +727,7 @@ BOOST_AUTO_TEST_CASE(strings_and_arrays)
|
||||
// bug #1801
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function f(string a, bytes b, uint[] c) external {}
|
||||
function f(string calldata a, bytes calldata b, uint[] calldata c) external {}
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -526,7 +526,7 @@ BOOST_AUTO_TEST_CASE(array_multiple_local_vars)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract test {
|
||||
function f(uint256[] seq) external pure returns (uint256) {
|
||||
function f(uint256[] calldata seq) external pure returns (uint256) {
|
||||
uint i = 0;
|
||||
uint sum = 0;
|
||||
while (i < seq.length)
|
||||
@ -4540,7 +4540,7 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
|
||||
struct Struct { uint a; bytes data; uint b; }
|
||||
Struct data1;
|
||||
Struct data2;
|
||||
function set(uint _a, bytes _data, uint _b) external returns (bool) {
|
||||
function set(uint _a, bytes calldata _data, uint _b) external returns (bool) {
|
||||
data1.a = _a;
|
||||
data1.b = _b;
|
||||
data1.data = _data;
|
||||
@ -4764,12 +4764,12 @@ BOOST_AUTO_TEST_CASE(struct_referencing)
|
||||
}
|
||||
library L {
|
||||
struct S { uint b; uint a; }
|
||||
function f() public pure returns (S) {
|
||||
function f() public pure returns (S memory) {
|
||||
S memory s;
|
||||
s.a = 3;
|
||||
return s;
|
||||
}
|
||||
function g() public pure returns (I.S) {
|
||||
function g() public pure returns (I.S memory) {
|
||||
I.S memory s;
|
||||
s.a = 4;
|
||||
return s;
|
||||
@ -4779,25 +4779,25 @@ BOOST_AUTO_TEST_CASE(struct_referencing)
|
||||
function a(S memory) public pure returns (uint) { return 2; }
|
||||
}
|
||||
contract C is I {
|
||||
function f() public pure returns (S) {
|
||||
function f() public pure returns (S memory) {
|
||||
S memory s;
|
||||
s.a = 1;
|
||||
return s;
|
||||
}
|
||||
function g() public pure returns (I.S) {
|
||||
function g() public pure returns (I.S memory) {
|
||||
I.S memory s;
|
||||
s.a = 2;
|
||||
return s;
|
||||
}
|
||||
function h() public pure returns (L.S) {
|
||||
function h() public pure returns (L.S memory) {
|
||||
L.S memory s;
|
||||
s.a = 5;
|
||||
return s;
|
||||
}
|
||||
function x() public pure returns (L.S) {
|
||||
function x() public pure returns (L.S memory) {
|
||||
return L.f();
|
||||
}
|
||||
function y() public pure returns (I.S) {
|
||||
function y() public pure returns (I.S memory) {
|
||||
return L.g();
|
||||
}
|
||||
function a1() public pure returns (uint) { S memory s; return L.a(s); }
|
||||
@ -4941,7 +4941,7 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments)
|
||||
uint result;
|
||||
function f(uint a, uint b) public { result += a + b; }
|
||||
function g(uint a) public { result *= a; }
|
||||
function test(uint a, bytes data1, bytes data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) {
|
||||
function test(uint a, bytes calldata data1, bytes calldata data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) {
|
||||
r_a = a;
|
||||
address(this).call(data1);
|
||||
address(this).call(data2);
|
||||
@ -5876,7 +5876,7 @@ BOOST_AUTO_TEST_CASE(external_array_args)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract c {
|
||||
function test(uint[8] a, uint[] b, uint[5] c, uint a_index, uint b_index, uint c_index)
|
||||
function test(uint[8] calldata a, uint[] calldata b, uint[5] calldata c, uint a_index, uint b_index, uint c_index)
|
||||
external returns (uint av, uint bv, uint cv) {
|
||||
av = a[a_index];
|
||||
bv = b[b_index];
|
||||
@ -5901,10 +5901,10 @@ BOOST_AUTO_TEST_CASE(bytes_index_access)
|
||||
char const* sourceCode = R"(
|
||||
contract c {
|
||||
bytes data;
|
||||
function direct(bytes arg, uint index) external returns (uint) {
|
||||
function direct(bytes calldata arg, uint index) external returns (uint) {
|
||||
return uint(uint8(arg[index]));
|
||||
}
|
||||
function storageCopyRead(bytes arg, uint index) external returns (uint) {
|
||||
function storageCopyRead(bytes calldata arg, uint index) external returns (uint) {
|
||||
data = arg;
|
||||
return uint(uint8(data[index]));
|
||||
}
|
||||
@ -5959,7 +5959,7 @@ BOOST_AUTO_TEST_CASE(array_copy_calldata_storage)
|
||||
uint[9] m_data;
|
||||
uint[] m_data_dyn;
|
||||
uint8[][] m_byte_data;
|
||||
function store(uint[9] a, uint8[3][] b) external returns (uint8) {
|
||||
function store(uint[9] calldata a, uint8[3][] calldata b) external returns (uint8) {
|
||||
m_data = a;
|
||||
m_data_dyn = a;
|
||||
m_byte_data = b;
|
||||
@ -5998,7 +5998,7 @@ BOOST_AUTO_TEST_CASE(array_copy_nested_array)
|
||||
uint[4][] a;
|
||||
uint[10][] b;
|
||||
uint[][] c;
|
||||
function test(uint[2][] d) external returns (uint) {
|
||||
function test(uint[2][] calldata d) external returns (uint) {
|
||||
a = d;
|
||||
b = a;
|
||||
c = b;
|
||||
@ -6949,7 +6949,7 @@ BOOST_AUTO_TEST_CASE(return_string)
|
||||
char const* sourceCode = R"(
|
||||
contract Main {
|
||||
string public s;
|
||||
function set(string _s) external {
|
||||
function set(string calldata _s) external {
|
||||
s = _s;
|
||||
}
|
||||
function get1() public returns (string memory r) {
|
||||
@ -6975,7 +6975,7 @@ BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes)
|
||||
contract Main {
|
||||
string public s1;
|
||||
string public s2;
|
||||
function set(string _s1, uint x, string _s2) external returns (uint) {
|
||||
function set(string calldata _s1, uint x, string calldata _s2) external returns (uint) {
|
||||
s1 = _s1;
|
||||
s2 = _s2;
|
||||
return x;
|
||||
@ -7024,7 +7024,7 @@ BOOST_AUTO_TEST_CASE(accessor_involving_strings)
|
||||
contract Main {
|
||||
struct stringData { string a; uint b; string c; }
|
||||
mapping(uint => stringData[]) public data;
|
||||
function set(uint x, uint y, string a, uint b, string c) external returns (bool) {
|
||||
function set(uint x, uint y, string calldata a, uint b, string calldata c) external returns (bool) {
|
||||
data[x].length = y + 1;
|
||||
data[x][y].a = a;
|
||||
data[x][y].b = b;
|
||||
@ -7061,7 +7061,7 @@ BOOST_AUTO_TEST_CASE(bytes_in_function_calls)
|
||||
function setIndirectFromMemory(string memory _s1, uint x, string memory _s2) public returns (uint) {
|
||||
return this.set(_s1, x, _s2);
|
||||
}
|
||||
function setIndirectFromCalldata(string _s1, uint x, string _s2) external returns (uint) {
|
||||
function setIndirectFromCalldata(string calldata _s1, uint x, string calldata _s2) external returns (uint) {
|
||||
return this.set(_s1, x, _s2);
|
||||
}
|
||||
}
|
||||
@ -7102,7 +7102,7 @@ BOOST_AUTO_TEST_CASE(return_bytes_internal)
|
||||
s1 = _s1;
|
||||
_r1 = s1;
|
||||
}
|
||||
function set(bytes _s1) external returns (uint _r, bytes memory _r1) {
|
||||
function set(bytes calldata _s1) external returns (uint _r, bytes memory _r1) {
|
||||
_r1 = doSet(_s1);
|
||||
_r = _r1.length;
|
||||
}
|
||||
@ -8040,7 +8040,7 @@ BOOST_AUTO_TEST_CASE(library_call)
|
||||
BOOST_AUTO_TEST_CASE(library_function_external)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
library Lib { function m(bytes b) external pure returns (byte) { return b[2]; } }
|
||||
library Lib { function m(bytes calldata b) external pure returns (byte) { return b[2]; } }
|
||||
contract Test {
|
||||
function f(bytes memory b) public pure returns (byte) {
|
||||
return Lib.m(b);
|
||||
|
@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(function_external_types)
|
||||
uint a;
|
||||
}
|
||||
contract Test {
|
||||
function boo(uint, bool, bytes8, bool[2], uint[], C, address[]) external returns (uint ret) {
|
||||
function boo(uint, bool, bytes8, bool[2] calldata, uint[] calldata, C, address[] calldata) external returns (uint ret) {
|
||||
ret = 5;
|
||||
}
|
||||
}
|
||||
@ -206,10 +206,10 @@ BOOST_AUTO_TEST_CASE(external_structs)
|
||||
struct Simple { uint i; }
|
||||
struct Nested { X[2][] a; uint y; }
|
||||
struct X { bytes32 x; Test t; Simple[] s; }
|
||||
function f(ActionChoices, uint, Simple) external {}
|
||||
function g(Test, Nested) external {}
|
||||
function h(function(Nested memory) external returns (uint)[]) external {}
|
||||
function i(Nested[]) external {}
|
||||
function f(ActionChoices, uint, Simple calldata) external {}
|
||||
function g(Test, Nested calldata) external {}
|
||||
function h(function(Nested memory) external returns (uint)[] calldata) external {}
|
||||
function i(Nested[] calldata) external {}
|
||||
}
|
||||
)";
|
||||
SourceUnit const* sourceUnit = parseAndAnalyse(text);
|
||||
@ -234,10 +234,10 @@ BOOST_AUTO_TEST_CASE(external_structs_in_libraries)
|
||||
struct Simple { uint i; }
|
||||
struct Nested { X[2][] a; uint y; }
|
||||
struct X { bytes32 x; Test t; Simple[] s; }
|
||||
function f(ActionChoices, uint, Simple) external {}
|
||||
function g(Test, Nested) external {}
|
||||
function h(function(Nested memory) external returns (uint)[]) external {}
|
||||
function i(Nested[]) external {}
|
||||
function f(ActionChoices, uint, Simple calldata) external {}
|
||||
function g(Test, Nested calldata) external {}
|
||||
function h(function(Nested memory) external returns (uint)[] calldata) external {}
|
||||
function i(Nested[] calldata) external {}
|
||||
}
|
||||
)";
|
||||
SourceUnit const* sourceUnit = parseAndAnalyse(text);
|
||||
@ -340,7 +340,7 @@ BOOST_AUTO_TEST_CASE(string)
|
||||
char const* sourceCode = R"(
|
||||
contract C {
|
||||
string s;
|
||||
function f(string x) external { s = x; }
|
||||
function f(string calldata x) external { s = x; }
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
|
||||
|
@ -4,4 +4,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (28-45): The "constant" keyword can only be used for state variables.
|
||||
// TypeError: (69-72): Invalid array length, expected integer literal or constant expression.
|
||||
|
@ -1,5 +1,5 @@
|
||||
contract test {
|
||||
function f() public pure returns (bytes) {
|
||||
function f() public pure returns (bytes memory) {
|
||||
return bytes("abc");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
library L {
|
||||
struct Nested { uint y; }
|
||||
function c(function(Nested memory) external returns (uint)[] storage) external pure {}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
library L {
|
||||
struct Nested { uint y; }
|
||||
function b(function(Nested calldata) external returns (uint)[] storage) external pure {}
|
||||
function d(function(Nested storage) external returns (uint)[] storage) external pure {}
|
||||
}
|
||||
|
||||
// ----
|
||||
// TypeError: (66-72): Data location must be "memory" for parameter in function, but "calldata" was given.
|
||||
// TypeError: (159-165): Data location must be "memory" for parameter in function, but "storage" was given.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function i() external pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (52-58): Data location must be "memory" for return parameter in function, but none was given.
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes memory) external;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-36): Location has to be calldata for external functions (remove the "memory" or "storage" keyword).
|
||||
// TypeError: (31-36): Data location must be "calldata" for parameter in external function, but "memory" was given.
|
||||
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes storage) external;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-36): Location has to be calldata for external functions (remove the "memory" or "storage" keyword).
|
||||
// TypeError: (31-36): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -1,5 +0,0 @@
|
||||
library test {
|
||||
function f(bytes calldata) public;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (30-35): Location cannot be calldata for non-external functions (remove the "calldata" keyword).
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes4 memory) public;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-37): Data location can only be given for array or struct types.
|
||||
// TypeError: (31-37): Data location can only be specified for array, struct or mapping types, but "memory" was given.
|
||||
|
@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
function f(uint[] memory, uint[] storage) private pure {}
|
||||
function g(uint[] memory, uint[] storage) internal pure {}
|
||||
function h(uint[] memory) public pure {}
|
||||
function i(uint[] calldata) external pure {}
|
||||
// No data location for events.
|
||||
event e(uint[]);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
contract C {
|
||||
function f() private pure returns(uint[] memory, uint[] storage b) { b = b; }
|
||||
function g() internal pure returns(uint[] memory, uint[] storage b) { b = b; }
|
||||
function h() public pure returns(uint[] memory) {}
|
||||
function i() external pure returns(uint[] memory) {}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
struct Nested { uint y; }
|
||||
// ensure that we consider array of function pointers as reference type
|
||||
function b(function(Nested memory) external returns (uint)[] storage) internal pure {}
|
||||
function c(function(Nested memory) external returns (uint)[] memory) public pure {}
|
||||
function d(function(Nested memory) external returns (uint)[] calldata) external pure {}
|
||||
}
|
||||
// ----
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes calldata) internal;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-36): Variable cannot be declared as "calldata" (remove the "calldata" keyword).
|
||||
// TypeError: (31-36): Data location must be "storage" or "memory" for parameter in function, but "calldata" was given.
|
||||
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function g(uint[]) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-34): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function g() internal pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (52-58): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
@ -0,0 +1,12 @@
|
||||
library L {
|
||||
struct S { uint x; }
|
||||
function g(uint[2]) external pure {}
|
||||
function h(uint[]) external pure {}
|
||||
function i(S) external pure {}
|
||||
function j(mapping(uint => uint)) external pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (52-59): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (93-99): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (133-134): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
||||
// TypeError: (168-189): Data location must be "storage" or "calldata" for parameter in external function, but none was given.
|
@ -0,0 +1,12 @@
|
||||
library L {
|
||||
struct S { uint x; }
|
||||
function g() external pure returns (uint[2]) {}
|
||||
function h() external pure returns (uint[]) {}
|
||||
function i() external pure returns (S) {}
|
||||
function j() external pure returns (mapping(uint => uint)) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (77-84): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (129-135): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (180-181): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (226-247): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
@ -0,0 +1,10 @@
|
||||
library L {
|
||||
struct S { uint x; }
|
||||
function f(uint[] memory, uint[] storage, S storage) private pure
|
||||
returns (mapping(uint => uint) storage a, S memory b, uint[] storage c) { return (a, b, c); }
|
||||
function g(uint[] memory, uint[] storage) internal pure
|
||||
returns (mapping(uint => uint) storage a, S memory b, uint[] storage c) { return (a, b, c); }
|
||||
function h(uint[] memory, uint[] storage) public pure returns (S storage x) { return x; }
|
||||
function i(uint[] calldata, uint[] storage) external pure returns (S storage x) {return x; }
|
||||
}
|
||||
// ----
|
@ -0,0 +1,20 @@
|
||||
library L {
|
||||
struct S { uint x; }
|
||||
function g() internal pure returns (uint[2]) {}
|
||||
function h() internal pure returns (uint[]) {}
|
||||
function i() internal pure returns (S) {}
|
||||
function j() internal pure returns (mapping(uint => uint)) {}
|
||||
function gp(uint[2]) internal pure {}
|
||||
function hp(uint[]) internal pure {}
|
||||
function ip(S) internal pure {}
|
||||
function jp(mapping(uint => uint)) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (77-84): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (129-135): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (180-181): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (226-247): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (268-275): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (310-316): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (351-352): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (387-408): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
@ -0,0 +1,20 @@
|
||||
library L {
|
||||
struct S { uint x; }
|
||||
function g() private pure returns (uint[2]) {}
|
||||
function h() private pure returns (uint[]) {}
|
||||
function i() private pure returns (S) {}
|
||||
function j() private pure returns (mapping(uint => uint)) {}
|
||||
function gp(uint[2]) private pure {}
|
||||
function hp(uint[]) private pure {}
|
||||
function ip(S) private pure {}
|
||||
function jp(mapping(uint => uint)) private pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (76-83): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (127-133): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (177-178): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (222-243): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (264-271): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (305-311): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (345-346): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (380-401): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
@ -0,0 +1,19 @@
|
||||
library L {
|
||||
struct S { uint x; }
|
||||
function g() private pure returns (uint[2]) {}
|
||||
function h() private pure returns (uint[]) {}
|
||||
function i() private pure returns (S) {}
|
||||
function j() private pure returns (mapping(uint => uint)) {}
|
||||
function gp(uint[2]) private pure {}
|
||||
function hp(uint[]) private pure {}
|
||||
function ip(S) private pure {}
|
||||
function jp(mapping(uint => uint)) private pure {}}
|
||||
// ----
|
||||
// TypeError: (76-83): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (127-133): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (177-178): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (222-243): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
||||
// TypeError: (264-271): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (305-311): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (345-346): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
||||
// TypeError: (380-401): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
@ -2,4 +2,4 @@ library test {
|
||||
function f(bytes memory) external;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (30-35): Location has to be calldata or storage for external library functions (remove the "memory" keyword).
|
||||
// TypeError: (30-35): Data location must be "storage" or "calldata" for parameter in external function, but "memory" was given.
|
||||
|
@ -2,4 +2,4 @@ library test {
|
||||
function f(bytes calldata) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (30-35): Variable cannot be declared as "calldata" (remove the "calldata" keyword).
|
||||
// TypeError: (30-35): Data location must be "storage" or "memory" for parameter in function, but "calldata" was given.
|
||||
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function f(uint[]) private pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-34): Data location must be "storage" or "memory" for parameter in function, but none was given.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function f() private pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-57): Data location must be "storage" or "memory" for return parameter in function, but none was given.
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes calldata) public;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-36): Location has to be memory for publicly visible functions (remove the "storage" or "calldata" keyword).
|
||||
// TypeError: (31-36): Data location must be "memory" for parameter in function, but "calldata" was given.
|
||||
|
@ -2,4 +2,4 @@ contract test {
|
||||
function f(bytes storage) public;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-36): Location has to be memory for publicly visible functions (remove the "storage" or "calldata" keyword).
|
||||
// TypeError: (31-36): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function h(uint[]) public pure {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-34): Data location must be "memory" for parameter in function, but none was given.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
function h() public pure returns(uint[]) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (50-56): Data location must be "memory" for return parameter in function, but none was given.
|
@ -7,7 +7,7 @@ contract test {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (48-63): Data location can only be given for array or struct types.
|
||||
// TypeError: (71-89): Data location can only be given for array or struct types.
|
||||
// TypeError: (97-111): Data location can only be given for array or struct types.
|
||||
// TypeError: (119-136): Data location can only be given for array or struct types.
|
||||
// TypeError: (48-63): Data location can only be specified for array, struct or mapping types, but "storage" was given.
|
||||
// TypeError: (71-89): Data location can only be specified for array, struct or mapping types, but "storage" was given.
|
||||
// TypeError: (97-111): Data location can only be specified for array, struct or mapping types, but "memory" was given.
|
||||
// TypeError: (119-136): Data location can only be specified for array, struct or mapping types, but "memory" was given.
|
||||
|
@ -3,7 +3,7 @@
|
||||
// when converting to a function type.
|
||||
contract C {
|
||||
function f(function(bytes memory) pure external /*g*/) pure public { }
|
||||
function callback(bytes) pure external {}
|
||||
function callback(bytes calldata) pure external {}
|
||||
function g() view public {
|
||||
f(this.callback);
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ contract test {
|
||||
function f(uint[] memory constant a) public { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (31-55): Illegal use of "constant" specifier.
|
||||
// DeclarationError: (31-55): The "constant" keyword can only be used for state variables.
|
||||
// TypeError: (31-55): Constants of non-value type not yet implemented.
|
||||
// TypeError: (31-55): Uninitialized "constant" variable.
|
||||
|
@ -1,8 +1,8 @@
|
||||
contract Vehicle {
|
||||
function f(bytes) external returns (uint256 r) {r = 1;}
|
||||
function f(bytes calldata) external returns (uint256 r) {r = 1;}
|
||||
}
|
||||
contract Bike is Vehicle {
|
||||
function f(bytes) external returns (uint256 r) {r = 42;}
|
||||
function f(bytes calldata) external returns (uint256 r) {r = 42;}
|
||||
}
|
||||
// ----
|
||||
// Warning: (23-78): Function state mutability can be restricted to pure
|
||||
// Warning: (23-87): Function state mutability can be restricted to pure
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function f(uint[] memory a) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-43): Location has to be calldata for external functions (remove the "memory" or "storage" keyword).
|
||||
// TypeError: (28-43): Data location must be "calldata" for parameter in external function, but "memory" was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function f(uint[] storage a) external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-44): Location has to be calldata for external functions (remove the "memory" or "storage" keyword).
|
||||
// TypeError: (28-44): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -1,17 +1,11 @@
|
||||
contract Test {
|
||||
string s;
|
||||
bytes b;
|
||||
function h(string _s) external { bytes(_s).length; }
|
||||
function i(string memory _s) internal { bytes(_s).length; }
|
||||
function j() internal { bytes(s).length; }
|
||||
function k(bytes _b) external { string(_b); }
|
||||
function l(bytes memory _b) internal { string(_b); }
|
||||
function m() internal { string(b); }
|
||||
function h(string calldata _s) pure external { bytes(_s).length; }
|
||||
function i(string memory _s) pure internal { bytes(_s).length; }
|
||||
function j() view internal { bytes(s).length; }
|
||||
function k(bytes calldata _b) pure external { string(_b); }
|
||||
function l(bytes memory _b) pure internal { string(_b); }
|
||||
function m() view internal { string(b); }
|
||||
}
|
||||
// ----
|
||||
// Warning: (47-99): Function state mutability can be restricted to pure
|
||||
// Warning: (104-163): Function state mutability can be restricted to pure
|
||||
// Warning: (168-210): Function state mutability can be restricted to view
|
||||
// Warning: (215-260): Function state mutability can be restricted to pure
|
||||
// Warning: (265-317): Function state mutability can be restricted to pure
|
||||
// Warning: (322-358): Function state mutability can be restricted to view
|
||||
|
@ -1,9 +1,9 @@
|
||||
contract C {
|
||||
function f(bytes bytesAsCalldata) external {
|
||||
function f(bytes calldata bytesAsCalldata) external {
|
||||
assembly {
|
||||
let x := bytesAsCalldata
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (102-117): Call data elements cannot be accessed directly. Copy to a local variable first or use "calldataload" or "calldatacopy" with manually determined offsets and sizes.
|
||||
// TypeError: (111-126): Call data elements cannot be accessed directly. Copy to a local variable first or use "calldataload" or "calldatacopy" with manually determined offsets and sizes.
|
||||
|
@ -9,5 +9,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (104-107): Data location must be specified as either "memory" or "storage".
|
||||
// TypeError: (123-131): Data location must be specified as either "memory" or "storage".
|
||||
// TypeError: (104-107): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
// TypeError: (123-131): Data location must be "storage" or "memory" for variable, but none was given.
|
||||
|
@ -2,4 +2,4 @@ contract C {
|
||||
function f(uint storage a) public { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-42): Data location can only be given for array or struct types.
|
||||
// TypeError: (28-42): Data location can only be specified for array, struct or mapping types, but "storage" was given.
|
||||
|
@ -4,4 +4,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-42): Data location can only be given for array or struct types.
|
||||
// TypeError: (28-42): Data location can only be specified for array, struct or mapping types, but "storage" was given.
|
||||
|
@ -1,6 +1,6 @@
|
||||
contract C {
|
||||
function f(uint[85678901234] a) pure external {
|
||||
function f(uint[85678901234] calldata a) pure external {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-47): Array is too large to be encoded.
|
||||
// TypeError: (28-56): Array is too large to be encoded.
|
||||
|
@ -0,0 +1,8 @@
|
||||
contract C {
|
||||
// This should probably have a better error message at some point.
|
||||
// Constant mappings should not be possible in general.
|
||||
mapping(uint => uint) constant x;
|
||||
}
|
||||
// ----
|
||||
// TypeError: (148-180): Constants of non-value type not yet implemented.
|
||||
// TypeError: (148-180): Uninitialized "constant" variable.
|
@ -2,4 +2,6 @@ contract Foo {
|
||||
function f(uint[] storage constant x, uint[] memory y) internal { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (30-55): Data location has to be "memory" (or unspecified) for constants.
|
||||
// DeclarationError: (30-55): The "constant" keyword can only be used for state variables.
|
||||
// TypeError: (30-55): Constants of non-value type not yet implemented.
|
||||
// TypeError: (30-55): Uninitialized "constant" variable.
|
||||
|
@ -3,5 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-49): Type is required to live outside storage.
|
||||
// TypeError: (28-49): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (28-49): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -3,5 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-49): Type is required to live outside storage.
|
||||
// TypeError: (28-49): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (28-49): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-51): Location has to be calldata for external functions (remove the "memory" or "storage" keyword).
|
||||
// TypeError: (28-51): Data location must be "calldata" for parameter in external function, but "storage" was given.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (28-51): Location has to be memory for publicly visible functions (remove the "storage" or "calldata" keyword).
|
||||
// TypeError: (28-51): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
|
@ -3,4 +3,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (37-56): Data location must be "memory" for parameter in function, but "storage" was given.
|
||||
// TypeError: (37-56): Internal type cannot be used for external function type.
|
||||
|
@ -3,4 +3,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (57-76): Data location must be "memory" for return parameter in function, but "storage" was given.
|
||||
// TypeError: (57-76): Internal type cannot be used for external function type.
|
||||
|
@ -0,0 +1,6 @@
|
||||
contract c {
|
||||
function f1(mapping(uint => uint)[] calldata) pure external {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (29-52): Type is required to live outside storage.
|
||||
// TypeError: (29-52): Internal or recursive type is not allowed for public or external functions.
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (53-84): Location has to be memory for publicly visible functions (remove the "storage" or "calldata" keyword).
|
||||
// TypeError: (53-84): Data location must be "memory" for return parameter in function, but "storage" was given.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-82): Location has to be memory for publicly visible functions (remove the "storage" or "calldata" keyword).
|
||||
// TypeError: (51-82): Data location must be "memory" for return parameter in function, but "storage" was given.
|
||||
|
@ -6,4 +6,4 @@ contract c {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (81-113): Data location for mappings must be specified as "storage".
|
||||
// TypeError: (81-113): Data location must be "storage" for variable, but "calldata" was given.
|
||||
|
@ -6,4 +6,4 @@ contract c {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (81-104): Data location for mappings must be specified as "storage".
|
||||
// TypeError: (81-104): Data location must be "storage" for variable, but none was given.
|
||||
|
@ -0,0 +1,6 @@
|
||||
contract c {
|
||||
function f1(mapping(uint => uint) calldata) pure external returns (mapping(uint => uint) memory) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (29-50): Type is required to live outside storage.
|
||||
// TypeError: (29-50): Internal or recursive type is not allowed for public or external functions.
|
@ -0,0 +1,4 @@
|
||||
contract c {
|
||||
function f4(mapping(uint => uint) memory) pure internal {}
|
||||
}
|
||||
// ----
|
@ -0,0 +1,6 @@
|
||||
contract c {
|
||||
function f3(mapping(uint => uint) memory) view public {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (29-50): Type is required to live outside storage.
|
||||
// TypeError: (29-50): Internal or recursive type is not allowed for public or external functions.
|
@ -6,4 +6,4 @@ contract c {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (81-111): Data location for mappings must be specified as "storage".
|
||||
// TypeError: (81-111): Data location must be "storage" for variable, but "memory" was given.
|
||||
|
@ -3,5 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (53-82): Type is required to live outside storage.
|
||||
// TypeError: (53-82): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (53-82): Data location must be "memory" for return parameter in function, but "storage" was given.
|
||||
|
@ -3,5 +3,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-80): Type is required to live outside storage.
|
||||
// TypeError: (51-80): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (51-80): Data location must be "memory" for return parameter in function, but "storage" was given.
|
||||
|
@ -0,0 +1,7 @@
|
||||
contract C {
|
||||
function f() public pure returns (mapping(uint=>uint) memory m) {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (51-79): Type is required to live outside storage.
|
||||
// TypeError: (51-79): Internal or recursive type is not allowed for public or external functions.
|
Loading…
Reference in New Issue
Block a user