mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7773 from ethereum/develop
Merge develop into develop_060
This commit is contained in:
commit
a00f824479
@ -37,6 +37,7 @@ Compiler Features:
|
|||||||
### 0.5.14 (unreleased)
|
### 0.5.14 (unreleased)
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
* Allow to obtain the selector of public or external library functions via a member ``.selector``.
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
@ -208,6 +208,48 @@ Restrictions for libraries in comparison to contracts:
|
|||||||
|
|
||||||
(These might be lifted at a later point.)
|
(These might be lifted at a later point.)
|
||||||
|
|
||||||
|
.. _library-selectors:
|
||||||
|
|
||||||
|
Function Signatures and Selectors in Libraries
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
While external calls to public or external library functions are possible, the calling convention for such calls
|
||||||
|
is considered to be internal to Solidity and not the same as specified for the regular :ref:`contract ABI<ABI>`.
|
||||||
|
External library functions support more argument types than external contract functions, for example recursive structs
|
||||||
|
and storage pointers. For that reason, the function signatures used to compute the 4-byte selector are computed
|
||||||
|
following an internal naming schema and arguments of types not supported in the contract ABI use an internal encoding.
|
||||||
|
|
||||||
|
The following identifiers are used for the types in the signatures:
|
||||||
|
|
||||||
|
- Value types, non-storage ``string`` and non-storage ``bytes`` use the same identifiers as in the contract ABI.
|
||||||
|
- Non-storage array types follow the same convention as in the contract ABI, i.e. ``<type>[]`` for dynamic arrays and
|
||||||
|
``<type>[M]`` for fixed-size arrays of ``M`` elements.
|
||||||
|
- Non-storage structs are referred to by their fully qualified name, i.e. ``C.S`` for ``contract C { struct S { ... } }``.
|
||||||
|
- Storage pointer types use the type identifier of their corresponding non-storage type, but append a single space
|
||||||
|
followed by ``storage`` to it.
|
||||||
|
|
||||||
|
The argument encoding is the same as for the regular contract ABI, except for storage pointers, which are encoded as a
|
||||||
|
``uint256`` value referring to the storage slot to which they point.
|
||||||
|
|
||||||
|
Similarly to the contract ABI, the selector consists of the first four bytes of the Keccak256-hash of the signature.
|
||||||
|
Its value can be obtained from Solidity using the ``.selector`` member as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pragma solidity >0.5.13 <0.7.0;
|
||||||
|
|
||||||
|
library L {
|
||||||
|
function f(uint256) external {}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function g() public pure returns (bytes4) {
|
||||||
|
return L.f.selector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _call-protection:
|
.. _call-protection:
|
||||||
|
|
||||||
Call Protection For Libraries
|
Call Protection For Libraries
|
||||||
|
@ -57,7 +57,7 @@ Either add ``--libraries "file.sol:Math:0x12345678901234567890123456789012345678
|
|||||||
|
|
||||||
If ``solc`` is called with the option ``--link``, all input files are interpreted to be unlinked binaries (hex-encoded) in the ``__$53aea86b7d70b31448b230b20ae141a537$__``-format given above and are linked in-place (if the input is read from stdin, it is written to stdout). All options except ``--libraries`` are ignored (including ``-o``) in this case.
|
If ``solc`` is called with the option ``--link``, all input files are interpreted to be unlinked binaries (hex-encoded) in the ``__$53aea86b7d70b31448b230b20ae141a537$__``-format given above and are linked in-place (if the input is read from stdin, it is written to stdout). All options except ``--libraries`` are ignored (including ``-o``) in this case.
|
||||||
|
|
||||||
If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses.
|
If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses. The process will always terminate in a "success" state and report any errors via the JSON output.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The library placeholder used to be the fully qualified name of the library itself
|
The library placeholder used to be the fully qualified name of the library itself
|
||||||
@ -140,6 +140,8 @@ The fields are generally subject to change,
|
|||||||
some are optional (as noted), but we try to only make backwards compatible changes.
|
some are optional (as noted), but we try to only make backwards compatible changes.
|
||||||
|
|
||||||
The compiler API expects a JSON formatted input and outputs the compilation result in a JSON formatted output.
|
The compiler API expects a JSON formatted input and outputs the compilation result in a JSON formatted output.
|
||||||
|
The standard error output is not used and the process will always terminate in a "success" state, even
|
||||||
|
if there were errors. Errors are always reported as part of the JSON output.
|
||||||
|
|
||||||
The following subsections describe the format through an example.
|
The following subsections describe the format through an example.
|
||||||
Comments are of course not permitted and used here only for explanatory purposes.
|
Comments are of course not permitted and used here only for explanatory purposes.
|
||||||
|
@ -171,7 +171,7 @@ and have to be in the same function as the loop (or both have to be at the
|
|||||||
top level).
|
top level).
|
||||||
The ``leave`` statement can only be used inside a function.
|
The ``leave`` statement can only be used inside a function.
|
||||||
The condition part of the for-loop has to evaluate to exactly one value.
|
The condition part of the for-loop has to evaluate to exactly one value.
|
||||||
Functions cannot be defined inside for loop init blocks.
|
Functions cannot be defined anywhere inside for loop init blocks.
|
||||||
|
|
||||||
Literals cannot be larger than the their type. The largest type defined is 256-bit wide.
|
Literals cannot be larger than the their type. The largest type defined is 256-bit wide.
|
||||||
|
|
||||||
|
@ -54,17 +54,17 @@ ostream& KnownState::stream(ostream& _out) const
|
|||||||
|
|
||||||
_out << "=== State ===" << endl;
|
_out << "=== State ===" << endl;
|
||||||
_out << "Stack height: " << dec << m_stackHeight << endl;
|
_out << "Stack height: " << dec << m_stackHeight << endl;
|
||||||
_out << "Equivalence classes: " << endl;
|
_out << "Equivalence classes:" << endl;
|
||||||
for (Id eqClass = 0; eqClass < m_expressionClasses->size(); ++eqClass)
|
for (Id eqClass = 0; eqClass < m_expressionClasses->size(); ++eqClass)
|
||||||
streamExpressionClass(_out, eqClass);
|
streamExpressionClass(_out, eqClass);
|
||||||
|
|
||||||
_out << "Stack: " << endl;
|
_out << "Stack:" << endl;
|
||||||
for (auto const& it: m_stackElements)
|
for (auto const& it: m_stackElements)
|
||||||
{
|
{
|
||||||
_out << " " << dec << it.first << ": ";
|
_out << " " << dec << it.first << ": ";
|
||||||
streamExpressionClass(_out, it.second);
|
streamExpressionClass(_out, it.second);
|
||||||
}
|
}
|
||||||
_out << "Storage: " << endl;
|
_out << "Storage:" << endl;
|
||||||
for (auto const& it: m_storageContent)
|
for (auto const& it: m_storageContent)
|
||||||
{
|
{
|
||||||
_out << " ";
|
_out << " ";
|
||||||
@ -72,7 +72,7 @@ ostream& KnownState::stream(ostream& _out) const
|
|||||||
_out << ": ";
|
_out << ": ";
|
||||||
streamExpressionClass(_out, it.second);
|
streamExpressionClass(_out, it.second);
|
||||||
}
|
}
|
||||||
_out << "Memory: " << endl;
|
_out << "Memory:" << endl;
|
||||||
for (auto const& it: m_memoryContent)
|
for (auto const& it: m_memoryContent)
|
||||||
{
|
{
|
||||||
_out << " ";
|
_out << " ";
|
||||||
|
@ -3007,6 +3007,20 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
);
|
);
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
case Kind::DelegateCall:
|
||||||
|
{
|
||||||
|
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration);
|
||||||
|
solAssert(functionDefinition, "");
|
||||||
|
solAssert(functionDefinition->visibility() != Declaration::Visibility::Private, "");
|
||||||
|
if (functionDefinition->visibility() != Declaration::Visibility::Internal)
|
||||||
|
{
|
||||||
|
auto const* contract = dynamic_cast<ContractDefinition const*>(m_declaration->scope());
|
||||||
|
solAssert(contract, "");
|
||||||
|
solAssert(contract->isLibrary(), "");
|
||||||
|
return {{"selector", TypeProvider::fixedBytes(4)}};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return MemberList::MemberMap();
|
return MemberList::MemberMap();
|
||||||
}
|
}
|
||||||
|
@ -437,7 +437,7 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
parserResult = std::move(obj.code);
|
parserResult = std::move(obj.code);
|
||||||
|
|
||||||
#ifdef SOL_OUTPUT_ASM
|
#ifdef SOL_OUTPUT_ASM
|
||||||
cout << "After optimizer: " << endl;
|
cout << "After optimizer:" << endl;
|
||||||
cout << yul::AsmPrinter()(*parserResult) << endl;
|
cout << yul::AsmPrinter()(*parserResult) << endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <libyul/optimiser/Disambiguator.h>
|
#include <libyul/optimiser/Disambiguator.h>
|
||||||
#include <libyul/optimiser/NameDisplacer.h>
|
#include <libyul/optimiser/NameDisplacer.h>
|
||||||
#include <libyul/optimiser/OptimiserStep.h>
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
|
||||||
|
|
||||||
#include <libyul/AsmParser.h>
|
#include <libyul/AsmParser.h>
|
||||||
#include <libyul/AsmAnalysis.h>
|
#include <libyul/AsmAnalysis.h>
|
||||||
@ -702,6 +703,7 @@ Object EVMToEWasmTranslator::run(Object const& _object)
|
|||||||
FunctionHoister::run(context, ast);
|
FunctionHoister::run(context, ast);
|
||||||
FunctionGrouper::run(context, ast);
|
FunctionGrouper::run(context, ast);
|
||||||
MainFunction{}(ast);
|
MainFunction{}(ast);
|
||||||
|
ForLoopConditionIntoBody::run(context, ast);
|
||||||
ExpressionSplitter::run(context, ast);
|
ExpressionSplitter::run(context, ast);
|
||||||
WordSizeTransform::run(m_dialect, ast, nameDispenser);
|
WordSizeTransform::run(m_dialect, ast, nameDispenser);
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ namespace yul
|
|||||||
* takes four u64 parameters and is supposed to return the logical disjunction
|
* takes four u64 parameters and is supposed to return the logical disjunction
|
||||||
* of them as a u64 value. If this name is already used somewhere, it is renamed.
|
* of them as a u64 value. If this name is already used somewhere, it is renamed.
|
||||||
*
|
*
|
||||||
* Prerequisite: Disambiguator, ExpressionSplitter
|
* Prerequisite: Disambiguator, ForLoopConditionIntoBody, ExpressionSplitter
|
||||||
*/
|
*/
|
||||||
class WordSizeTransform: public ASTModifier
|
class WordSizeTransform: public ASTModifier
|
||||||
{
|
{
|
||||||
|
@ -294,7 +294,7 @@ void CommandLineInterface::handleBinary(string const& _contract)
|
|||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", objectWithLinkRefsHex(m_compiler->object(_contract)));
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", objectWithLinkRefsHex(m_compiler->object(_contract)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sout() << "Binary: " << endl;
|
sout() << "Binary:" << endl;
|
||||||
sout() << objectWithLinkRefsHex(m_compiler->object(_contract)) << endl;
|
sout() << objectWithLinkRefsHex(m_compiler->object(_contract)) << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,7 +304,7 @@ void CommandLineInterface::handleBinary(string const& _contract)
|
|||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)));
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sout() << "Binary of the runtime part: " << endl;
|
sout() << "Binary of the runtime part:" << endl;
|
||||||
sout() << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << endl;
|
sout() << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ void CommandLineInterface::handleOpcode(string const& _contract)
|
|||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".opcode", dev::eth::disassemble(m_compiler->object(_contract).bytecode));
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".opcode", dev::eth::disassemble(m_compiler->object(_contract).bytecode));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sout() << "Opcodes: " << endl;
|
sout() << "Opcodes:" << endl;
|
||||||
sout() << std::uppercase << dev::eth::disassemble(m_compiler->object(_contract).bytecode);
|
sout() << std::uppercase << dev::eth::disassemble(m_compiler->object(_contract).bytecode);
|
||||||
sout() << endl;
|
sout() << endl;
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ void CommandLineInterface::handleIR(string const& _contractName)
|
|||||||
createFile(m_compiler->filesystemFriendlyName(_contractName) + ".yul", m_compiler->yulIR(_contractName));
|
createFile(m_compiler->filesystemFriendlyName(_contractName) + ".yul", m_compiler->yulIR(_contractName));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sout() << "IR: " << endl;
|
sout() << "IR:" << endl;
|
||||||
sout() << m_compiler->yulIR(_contractName) << endl;
|
sout() << m_compiler->yulIR(_contractName) << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,7 +350,7 @@ void CommandLineInterface::handleEWasm(string const& _contractName)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sout() << "EWasm text: " << endl;
|
sout() << "EWasm text:" << endl;
|
||||||
sout() << m_compiler->eWasm(_contractName) << endl;
|
sout() << m_compiler->eWasm(_contractName) << endl;
|
||||||
sout() << "EWasm binary (hex): " << m_compiler->eWasmObject(_contractName).toHex() << endl;
|
sout() << "EWasm binary (hex): " << m_compiler->eWasmObject(_contractName).toHex() << endl;
|
||||||
}
|
}
|
||||||
@ -378,7 +378,7 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract)
|
|||||||
if (m_args.count(g_argOutputDir))
|
if (m_args.count(g_argOutputDir))
|
||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out);
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out);
|
||||||
else
|
else
|
||||||
sout() << "Function signatures: " << endl << out;
|
sout() << "Function signatures:" << endl << out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::handleMetadata(string const& _contract)
|
void CommandLineInterface::handleMetadata(string const& _contract)
|
||||||
@ -390,7 +390,7 @@ void CommandLineInterface::handleMetadata(string const& _contract)
|
|||||||
if (m_args.count(g_argOutputDir))
|
if (m_args.count(g_argOutputDir))
|
||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + "_meta.json", data);
|
createFile(m_compiler->filesystemFriendlyName(_contract) + "_meta.json", data);
|
||||||
else
|
else
|
||||||
sout() << "Metadata: " << endl << data << endl;
|
sout() << "Metadata:" << endl << data << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::handleABI(string const& _contract)
|
void CommandLineInterface::handleABI(string const& _contract)
|
||||||
@ -402,7 +402,7 @@ void CommandLineInterface::handleABI(string const& _contract)
|
|||||||
if (m_args.count(g_argOutputDir))
|
if (m_args.count(g_argOutputDir))
|
||||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".abi", data);
|
createFile(m_compiler->filesystemFriendlyName(_contract) + ".abi", data);
|
||||||
else
|
else
|
||||||
sout() << "Contract JSON ABI " << endl << data << endl;
|
sout() << "Contract JSON ABI" << endl << data << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contract)
|
void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contract)
|
||||||
@ -586,7 +586,7 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
|
|||||||
addrString = addrString.substr(2);
|
addrString = addrString.substr(2);
|
||||||
if (addrString.empty())
|
if (addrString.empty())
|
||||||
{
|
{
|
||||||
serr() << "Empty address provided for library \"" << libName << "\": " << endl;
|
serr() << "Empty address provided for library \"" << libName << "\":" << endl;
|
||||||
serr() << "Note that there should not be any whitespace after the colon." << endl;
|
serr() << "Note that there should not be any whitespace after the colon." << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256[] storage x) public pure returns (uint256) {
|
||||||
|
return 23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
uint256[] y;
|
||||||
|
string x;
|
||||||
|
constructor() public { y.push(42); }
|
||||||
|
function f() public view returns (uint256) {
|
||||||
|
return L.f(y);
|
||||||
|
}
|
||||||
|
function g() public returns (bool, uint256) {
|
||||||
|
uint256 ys;
|
||||||
|
assembly { ys := y_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
function h() public returns (bool, uint256) {
|
||||||
|
uint256 ys;
|
||||||
|
assembly { ys := y_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> 23
|
||||||
|
// g() -> true, 23
|
||||||
|
// h() -> true, 23
|
@ -0,0 +1,32 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256[] storage x) public view returns (uint256) {
|
||||||
|
return x.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
uint256[] y;
|
||||||
|
string x;
|
||||||
|
constructor() public { y.push(42); }
|
||||||
|
function f() public view returns (uint256) {
|
||||||
|
return L.f(y);
|
||||||
|
}
|
||||||
|
function g() public returns (bool, uint256) {
|
||||||
|
uint256 ys;
|
||||||
|
assembly { ys := y_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
function h() public returns (bool, uint256) {
|
||||||
|
uint256 ys;
|
||||||
|
assembly { ys := y_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> 1
|
||||||
|
// g() -> true, 1
|
||||||
|
// h() -> true, 0 # this is bad - this should fail! #
|
@ -0,0 +1,31 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256[] storage x) public view returns (uint256) {
|
||||||
|
return 84;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
uint256[] y;
|
||||||
|
constructor() public { y.push(42); }
|
||||||
|
function f() public view returns (uint256) {
|
||||||
|
return L.f(y);
|
||||||
|
}
|
||||||
|
function g() public returns (bool, uint256) {
|
||||||
|
uint256 ys;
|
||||||
|
assembly { ys := y_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
function h() public returns (bool, uint256) {
|
||||||
|
uint256 ys;
|
||||||
|
assembly { ys := y_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> 84
|
||||||
|
// g() -> true, 84
|
||||||
|
// h() -> true, 84
|
@ -0,0 +1,31 @@
|
|||||||
|
contract D {
|
||||||
|
uint public x;
|
||||||
|
constructor() public { x = 42; }
|
||||||
|
}
|
||||||
|
library L {
|
||||||
|
function f(D d) public view returns (uint256) {
|
||||||
|
return d.x();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
D d;
|
||||||
|
constructor() public { d = new D(); }
|
||||||
|
function f() public view returns (uint256) {
|
||||||
|
return L.f(d);
|
||||||
|
}
|
||||||
|
function g() public returns (bool, uint256) {
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, d));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
function h() public returns (bool, uint256) {
|
||||||
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, d));
|
||||||
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> 42
|
||||||
|
// g() -> true, 42
|
||||||
|
// h() -> true, 42
|
@ -0,0 +1,30 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256 x) external returns (uint) { return x; }
|
||||||
|
function g(uint256[] storage s) external returns (uint) { return s.length; }
|
||||||
|
function h(uint256[] memory m) public returns (uint) { return m.length; }
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
uint256[] s;
|
||||||
|
constructor() public { while (s.length < 42) s.push(0); }
|
||||||
|
function f() public returns (bool, bool, uint256) {
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, 7));
|
||||||
|
return (L.f.selector == bytes4(keccak256("f(uint256)")), success, abi.decode(data, (uint256)));
|
||||||
|
}
|
||||||
|
function g() public returns (bool, bool, uint256) {
|
||||||
|
uint256 s_ptr;
|
||||||
|
assembly { s_ptr := s_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.g.selector, s_ptr));
|
||||||
|
return (L.g.selector == bytes4(keccak256("g(uint256[] storage)")), success, abi.decode(data, (uint256)));
|
||||||
|
}
|
||||||
|
function h() public returns (bool, bool, uint256) {
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.h.selector, new uint256[](23)));
|
||||||
|
return (L.h.selector == bytes4(keccak256("h(uint256[])")), success, abi.decode(data, (uint256)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> true, true, 7
|
||||||
|
// g() -> true, true, 42
|
||||||
|
// h() -> true, true, 23
|
@ -0,0 +1,27 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
library L {
|
||||||
|
struct S { uint256 a; }
|
||||||
|
function f(S storage s) external returns (uint) { return s.a; }
|
||||||
|
function g(S memory m) public returns (uint) { return m.a; }
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
L.S s;
|
||||||
|
constructor() public { s.a = 42; }
|
||||||
|
|
||||||
|
function f() public returns (bool, bool, uint256) {
|
||||||
|
uint256 s_ptr;
|
||||||
|
assembly { s_ptr := s_slot }
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, s_ptr));
|
||||||
|
return (L.f.selector == bytes4(keccak256("f(L.S storage)")), success, abi.decode(data, (uint256)));
|
||||||
|
}
|
||||||
|
function g() public returns (bool, bool, uint256) {
|
||||||
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.g.selector, L.S(23)));
|
||||||
|
return (L.g.selector == bytes4(keccak256("g(L.S)")), success, abi.decode(data, (uint256)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> true, true, 42
|
||||||
|
// g() -> true, true, 23
|
@ -0,0 +1,13 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256) external {}
|
||||||
|
function g(uint256[] storage) external {}
|
||||||
|
function h(uint256[] memory) public {}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (bytes4 a, bytes4 b, bytes4 c, bytes4 d) {
|
||||||
|
a = L.f.selector;
|
||||||
|
b = L.g.selector;
|
||||||
|
c = L.h.selector;
|
||||||
|
d = L.h.selector;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256) internal {}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (bytes4) {
|
||||||
|
return L.f.selector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (126-138): Member "selector" not found or not visible after argument-dependent lookup in function (uint256).
|
@ -0,0 +1,8 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256) private {}
|
||||||
|
function g(uint256) public returns (uint256) {
|
||||||
|
return f.selector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (113-123): Member "selector" not found or not visible after argument-dependent lookup in function (uint256).
|
@ -0,0 +1,10 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256) private {}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (bytes4) {
|
||||||
|
return L.f.selector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (125-128): Member "f" not found or not visible after argument-dependent lookup in type(library L).
|
@ -0,0 +1,10 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256) external pure {}
|
||||||
|
function g(uint256) external view {}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (bytes4, bytes4) {
|
||||||
|
return (L.f.selector, L.g.selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
@ -140,7 +140,7 @@ public:
|
|||||||
cout << " (e)xpr inline/(i)nline/(s)implify/varname c(l)eaner/(u)nusedprune/ss(a) transform/" << endl;
|
cout << " (e)xpr inline/(i)nline/(s)implify/varname c(l)eaner/(u)nusedprune/ss(a) transform/" << endl;
|
||||||
cout << " (r)edundant assign elim./re(m)aterializer/f(o)r-loop-init-rewriter/for-loop-condition-(I)nto-body/" << endl;
|
cout << " (r)edundant assign elim./re(m)aterializer/f(o)r-loop-init-rewriter/for-loop-condition-(I)nto-body/" << endl;
|
||||||
cout << " for-loop-condition-(O)ut-of-body/s(t)ructural simplifier/equi(v)alent function combiner/ssa re(V)erser/" << endl;
|
cout << " for-loop-condition-(O)ut-of-body/s(t)ructural simplifier/equi(v)alent function combiner/ssa re(V)erser/" << endl;
|
||||||
cout << " co(n)trol flow simplifier/stack com(p)ressor/(D)ead code eliminator/(L)oad resolver/ " << endl;
|
cout << " co(n)trol flow simplifier/stack com(p)ressor/(D)ead code eliminator/(L)oad resolver/" << endl;
|
||||||
cout << " (C)onditional simplifier?" << endl;
|
cout << " (C)onditional simplifier?" << endl;
|
||||||
cout.flush();
|
cout.flush();
|
||||||
int option = readStandardInputChar();
|
int option = readStandardInputChar();
|
||||||
|
Loading…
Reference in New Issue
Block a user