mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into HEAD
This commit is contained in:
@@ -26,8 +26,6 @@
|
||||
#include <libsolutil/JSON.h>
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
@@ -85,16 +83,3 @@ void ABIJsonTest::printUpdatedExpectations(ostream& _stream, string const& _line
|
||||
{
|
||||
printIndented(_stream, m_obtainedResult, _linePrefix);
|
||||
}
|
||||
|
||||
void ABIJsonTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const
|
||||
{
|
||||
stringstream output(_output);
|
||||
string line;
|
||||
while (getline(output, line))
|
||||
if (line.empty())
|
||||
// Avoid trailing spaces.
|
||||
_stream << boost::trim_right_copy(_linePrefix) << endl;
|
||||
else
|
||||
_stream << _linePrefix << line << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@ public:
|
||||
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
|
||||
|
||||
private:
|
||||
void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const;
|
||||
|
||||
std::string m_source;
|
||||
std::string m_expectation;
|
||||
std::string m_obtainedResult;
|
||||
|
||||
@@ -1126,12 +1126,14 @@ BOOST_AUTO_TEST_CASE(log0)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_CHECK_EQUAL(numLogTopics(0), 0);
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_CHECK_EQUAL(numLogTopics(0), 0);
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(log1)
|
||||
@@ -1143,13 +1145,15 @@ BOOST_AUTO_TEST_CASE(log1)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), h256(u256(2)));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), h256(u256(2)));
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(log2)
|
||||
@@ -1161,14 +1165,16 @@ BOOST_AUTO_TEST_CASE(log2)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
|
||||
for (unsigned i = 0; i < 2; ++i)
|
||||
BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
|
||||
for (unsigned i = 0; i < 2; ++i)
|
||||
BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(log3)
|
||||
@@ -1180,14 +1186,16 @@ BOOST_AUTO_TEST_CASE(log3)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(log4)
|
||||
@@ -1199,14 +1207,16 @@ BOOST_AUTO_TEST_CASE(log4)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 4);
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("a()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 4);
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(log_in_constructor)
|
||||
@@ -1218,12 +1228,14 @@ BOOST_AUTO_TEST_CASE(log_in_constructor)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), h256(u256(2)));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), h256(u256(2)));
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(selfdestruct)
|
||||
@@ -1238,11 +1250,13 @@ BOOST_AUTO_TEST_CASE(selfdestruct)
|
||||
}
|
||||
)";
|
||||
u256 amount(130);
|
||||
compileAndRun(sourceCode, amount);
|
||||
u160 address(23);
|
||||
ABI_CHECK(callContractFunction("a(address)", address), bytes());
|
||||
BOOST_CHECK(!addressHasCode(m_contractAddress));
|
||||
BOOST_CHECK_EQUAL(balanceAt(address), amount);
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode, amount);
|
||||
ABI_CHECK(callContractFunction("a(address)", address), bytes());
|
||||
BOOST_CHECK(!addressHasCode(m_contractAddress));
|
||||
BOOST_CHECK_EQUAL(balanceAt(address), amount);
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(keccak256)
|
||||
@@ -1774,20 +1788,22 @@ BOOST_AUTO_TEST_CASE(event)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
u256 value(18);
|
||||
u256 id(0x1234);
|
||||
for (bool manually: {true, false})
|
||||
{
|
||||
callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually);
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)")));
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id));
|
||||
}
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
u256 value(18);
|
||||
u256 id(0x1234);
|
||||
for (bool manually: {true, false})
|
||||
{
|
||||
callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually);
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value)));
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)")));
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id));
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(event_emit)
|
||||
@@ -1801,7 +1817,7 @@ BOOST_AUTO_TEST_CASE(event_emit)
|
||||
}
|
||||
)";
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
compileAndRun(sourceCode);
|
||||
u256 value(18);
|
||||
u256 id(0x1234);
|
||||
callContractFunctionWithValue("deposit(bytes32)", value, id);
|
||||
@@ -1850,13 +1866,15 @@ BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit)
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("f()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK(logData(0).empty());
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("x()")));
|
||||
ALSO_VIA_YUL(
|
||||
compileAndRun(sourceCode);
|
||||
callContractFunction("f()");
|
||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||
BOOST_CHECK(logData(0).empty());
|
||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
|
||||
BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("x()")));
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(events_with_same_name)
|
||||
|
||||
@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
|
||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
BOOST_REQUIRE(contract);
|
||||
BOOST_CHECK(!contract->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!contract->annotation().unimplementedDeclarations.empty());
|
||||
BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented());
|
||||
}
|
||||
|
||||
@@ -68,10 +68,10 @@ BOOST_AUTO_TEST_CASE(abstract_contract)
|
||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||
BOOST_REQUIRE(base);
|
||||
BOOST_CHECK(!base->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!base->annotation().unimplementedDeclarations.empty());
|
||||
BOOST_CHECK(!base->definedFunctions()[0]->isImplemented());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(derived->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(derived->annotation().unimplementedDeclarations.empty());
|
||||
BOOST_CHECK(derived->definedFunctions()[0]->isImplemented());
|
||||
}
|
||||
|
||||
@@ -87,9 +87,9 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
|
||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||
BOOST_REQUIRE(base);
|
||||
BOOST_CHECK(!base->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!base->annotation().unimplementedDeclarations.empty());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(!derived->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!derived->annotation().unimplementedDeclarations.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
||||
@@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
||||
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||
BOOST_REQUIRE(derived);
|
||||
BOOST_CHECK(!derived->annotation().unimplementedFunctions.empty());
|
||||
BOOST_CHECK(!derived->annotation().unimplementedDeclarations.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
||||
|
||||
@@ -21,11 +21,15 @@
|
||||
|
||||
#include <string>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <test/Metadata.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::evmasm;
|
||||
|
||||
@@ -1058,8 +1062,12 @@ BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
|
||||
BOOST_CHECK(optimizer["details"]["peephole"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yul"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"].isObject());
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"].getMemberNames() == vector<string>{"stackAllocation"});
|
||||
BOOST_CHECK(
|
||||
util::convertContainer<set<string>>(optimizer["details"]["yulDetails"].getMemberNames()) ==
|
||||
(set<string>{"stackAllocation", "optimizerSteps"})
|
||||
);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["stackAllocation"].asBool() == true);
|
||||
BOOST_CHECK(optimizer["details"]["yulDetails"]["optimizerSteps"].asString() == OptimiserSettings::DefaultYulOptimiserSteps);
|
||||
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 8);
|
||||
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
|
||||
}
|
||||
|
||||
@@ -17,5 +17,7 @@ contract B {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004
|
||||
|
||||
@@ -41,5 +41,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 5, 6, 7
|
||||
|
||||
@@ -3,6 +3,7 @@ contract C {
|
||||
return sha256("");
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
contract A {
|
||||
uint x = 42;
|
||||
function f() public returns(uint256) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
uint public y = f();
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// constructor() ->
|
||||
// y() -> 42
|
||||
@@ -0,0 +1,17 @@
|
||||
contract A {
|
||||
uint x;
|
||||
constructor() public {
|
||||
x = 42;
|
||||
}
|
||||
function f() public returns(uint256) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
uint public y = f();
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// constructor() ->
|
||||
// y() -> 42
|
||||
@@ -0,0 +1,28 @@
|
||||
contract A {
|
||||
uint public i;
|
||||
uint public k;
|
||||
|
||||
constructor(uint newI, uint newK) public {
|
||||
i = newI;
|
||||
k = newK;
|
||||
}
|
||||
}
|
||||
abstract contract B is A {
|
||||
uint public j;
|
||||
constructor(uint newJ) public {
|
||||
j = newJ;
|
||||
}
|
||||
}
|
||||
contract C is A {
|
||||
constructor(uint newI, uint newK) A(newI, newK) public {}
|
||||
}
|
||||
contract D is B, C {
|
||||
constructor(uint newI, uint newK) B(newI) C(newI, newK + 1) public {}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 2, 0 ->
|
||||
// i() -> 2
|
||||
// j() -> 2
|
||||
// k() -> 1
|
||||
@@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
uint public k;
|
||||
|
||||
constructor(uint newI, uint newK) public {
|
||||
i = newI;
|
||||
k = newK;
|
||||
}
|
||||
}
|
||||
contract D is C {
|
||||
constructor(uint newI, uint newK) C(newI, newK + 1) public {}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 2, 0 ->
|
||||
// i() -> 2
|
||||
// k() -> 1
|
||||
@@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
uint public k;
|
||||
|
||||
constructor(uint newI, uint newK) public {
|
||||
i = newI;
|
||||
k = newK;
|
||||
}
|
||||
}
|
||||
contract D is C(2, 1) {}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// i() -> 2
|
||||
// k() -> 1
|
||||
@@ -34,6 +34,8 @@ contract Child is Base {
|
||||
BaseBase.init(c, d);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x() -> 0
|
||||
// y() -> 0
|
||||
|
||||
@@ -18,6 +18,8 @@ contract Child is Base {
|
||||
Base.init(c, d);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x() -> 0
|
||||
// y() -> 0
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
contract test {
|
||||
bool public flag = false;
|
||||
|
||||
function f0() public {
|
||||
flag = true;
|
||||
}
|
||||
|
||||
function f() public returns (bool) {
|
||||
function() internal x = f0;
|
||||
x();
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
||||
// flag() -> true
|
||||
@@ -0,0 +1,15 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
constructor() public {
|
||||
i = 2;
|
||||
}
|
||||
}
|
||||
contract D {
|
||||
function f() public returns (uint r) {
|
||||
return new C().i();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
@@ -0,0 +1,20 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
constructor(uint newI) public {
|
||||
i = newI;
|
||||
}
|
||||
}
|
||||
contract D {
|
||||
C c;
|
||||
constructor(uint v) public {
|
||||
c = new C(v);
|
||||
}
|
||||
function f() public returns (uint r) {
|
||||
return c.i();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 2 ->
|
||||
// f() -> 2
|
||||
@@ -0,0 +1,21 @@
|
||||
contract C {
|
||||
uint public i;
|
||||
constructor(uint newI) public {
|
||||
i = newI;
|
||||
}
|
||||
}
|
||||
contract D {
|
||||
C c;
|
||||
constructor(uint v) public {
|
||||
c = new C{salt: "abc"}(v);
|
||||
}
|
||||
function f() public returns (uint r) {
|
||||
return c.i();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=constantinople
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 2 ->
|
||||
// f() -> 2
|
||||
@@ -36,8 +36,10 @@ contract test {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(), 20 wei ->
|
||||
// sendAmount(uint256): 5 -> 5
|
||||
// outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway #
|
||||
// checkState() -> false, 15
|
||||
// checkState() -> false, 15
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
interface ERC165 {
|
||||
/// @notice Query if a contract implements an interface
|
||||
/// @param interfaceID The interface identifier, as specified in ERC-165
|
||||
/// @dev Interface identification is specified in ERC-165. This function
|
||||
/// uses less than 30,000 gas.
|
||||
/// @return `true` if the contract implements `interfaceID` and
|
||||
/// `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
||||
|
||||
interface Simpson {
|
||||
function is2D() external returns (bool);
|
||||
function skinColor() external returns (string memory);
|
||||
}
|
||||
|
||||
contract Homer is ERC165, Simpson {
|
||||
function supportsInterface(bytes4 interfaceID) external view override returns (bool) {
|
||||
return
|
||||
interfaceID == this.supportsInterface.selector || // ERC165
|
||||
interfaceID == this.is2D.selector ^ this.skinColor.selector; // Simpson
|
||||
}
|
||||
|
||||
function is2D() external override returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function skinColor() external override returns (string memory) {
|
||||
return "yellow";
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// supportsInterface(bytes4): left(0x01ffc9a0) -> false
|
||||
// supportsInterface(bytes4): left(0x01ffc9a7) -> true
|
||||
// supportsInterface(bytes4): left(0x73b6b492) -> true
|
||||
// supportsInterface(bytes4): left(0x70b6b492) -> false
|
||||
@@ -0,0 +1,36 @@
|
||||
interface ERC165 {
|
||||
/// @notice Query if a contract implements an interface
|
||||
/// @param interfaceID The interface identifier, as specified in ERC-165
|
||||
/// @dev Interface identification is specified in ERC-165. This function
|
||||
/// uses less than 30,000 gas.
|
||||
/// @return `true` if the contract implements `interfaceID` and
|
||||
/// `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
||||
|
||||
interface Simpson {
|
||||
function is2D() external returns (bool);
|
||||
function skinColor() external returns (string memory);
|
||||
}
|
||||
|
||||
contract Homer is ERC165, Simpson {
|
||||
function supportsInterface(bytes4 interfaceID) external view override returns (bool) {
|
||||
return
|
||||
interfaceID == type(ERC165).interfaceId ||
|
||||
interfaceID == type(Simpson).interfaceId;
|
||||
}
|
||||
|
||||
function is2D() external override returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function skinColor() external override returns (string memory) {
|
||||
return "yellow";
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// supportsInterface(bytes4): left(0x01ffc9a0) -> false
|
||||
// supportsInterface(bytes4): left(0x01ffc9a7) -> true
|
||||
// supportsInterface(bytes4): left(0x73b6b492) -> true
|
||||
// supportsInterface(bytes4): left(0x70b6b492) -> false
|
||||
@@ -0,0 +1,21 @@
|
||||
interface HelloWorld {
|
||||
function hello() external pure;
|
||||
function world(int) external pure;
|
||||
}
|
||||
|
||||
interface HelloWorldWithEvent {
|
||||
event Event();
|
||||
function hello() external pure;
|
||||
function world(int) external pure;
|
||||
}
|
||||
|
||||
contract Test {
|
||||
bytes4 public hello_world = type(HelloWorld).interfaceId;
|
||||
bytes4 public hello_world_with_event = type(HelloWorldWithEvent).interfaceId;
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// hello_world() -> left(0xc6be8b58)
|
||||
// hello_world_with_event() -> left(0xc6be8b58)
|
||||
@@ -0,0 +1,67 @@
|
||||
interface HelloWorld {
|
||||
function hello() external pure;
|
||||
function world(int) external pure;
|
||||
}
|
||||
|
||||
interface HelloWorldDerived is HelloWorld {
|
||||
function other() external pure;
|
||||
}
|
||||
|
||||
interface ERC165 {
|
||||
/// @notice Query if a contract implements an interface
|
||||
/// @param interfaceID The interface identifier, as specified in ERC-165
|
||||
/// @dev Interface identification is specified in ERC-165. This function
|
||||
/// uses less than 30,000 gas.
|
||||
/// @return `true` if the contract implements `interfaceID` and
|
||||
/// `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
||||
|
||||
contract Test {
|
||||
bytes4 public ghello_world_interfaceId = type(HelloWorld).interfaceId;
|
||||
bytes4 public ERC165_interfaceId = type(ERC165).interfaceId;
|
||||
|
||||
function hello() public pure returns (bytes4 data){
|
||||
HelloWorld i;
|
||||
return i.hello.selector;
|
||||
}
|
||||
|
||||
function world() public pure returns (bytes4 data){
|
||||
HelloWorld i;
|
||||
return i.world.selector;
|
||||
}
|
||||
|
||||
function hello_world() public pure returns (bytes4 data){
|
||||
// HelloWorld i;
|
||||
// return i.hello.selector ^ i.world.selector; // = 0xc6be8b58
|
||||
return 0xc6be8b58;
|
||||
}
|
||||
|
||||
function hello_world_interfaceId() public pure returns (bytes4 data){
|
||||
return type(HelloWorld).interfaceId;
|
||||
}
|
||||
|
||||
function other() public pure returns (bytes4 data){
|
||||
HelloWorldDerived i;
|
||||
return i.other.selector;
|
||||
}
|
||||
|
||||
function hello_world_derived_interfaceId() public pure returns (bytes4 data){
|
||||
return type(HelloWorldDerived).interfaceId;
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// hello() -> left(0x19ff1d21)
|
||||
// world() -> left(0xdf419679)
|
||||
//
|
||||
// ERC165_interfaceId() -> left(0x01ffc9a7)
|
||||
//
|
||||
// hello_world() -> left(0xc6be8b58)
|
||||
// hello_world_interfaceId() -> left(0xc6be8b58)
|
||||
// ghello_world_interfaceId() -> left(0xc6be8b58)
|
||||
//
|
||||
// other() -> left(0x85295877)
|
||||
// hello_world_derived_interfaceId() -> left(0x85295877)
|
||||
@@ -0,0 +1,47 @@
|
||||
interface ERC165 {
|
||||
/// @notice Query if a contract implements an interface
|
||||
/// @param interfaceID The interface identifier, as specified in ERC-165
|
||||
/// @dev Interface identification is specified in ERC-165. This function
|
||||
/// uses less than 30,000 gas.
|
||||
/// @return `true` if the contract implements `interfaceID` and
|
||||
/// `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
||||
|
||||
contract ERC165MappingImplementation is ERC165 {
|
||||
/// @dev You must not set element 0xffffffff to true
|
||||
mapping(bytes4 => bool) internal supportedInterfaces;
|
||||
|
||||
constructor() internal {
|
||||
supportedInterfaces[this.supportsInterface.selector] = true;
|
||||
}
|
||||
|
||||
function supportsInterface(bytes4 interfaceID) external view override returns (bool) {
|
||||
return supportedInterfaces[interfaceID];
|
||||
}
|
||||
}
|
||||
|
||||
interface Simpson {
|
||||
function is2D() external returns (bool);
|
||||
function skinColor() external returns (string memory);
|
||||
}
|
||||
|
||||
contract Lisa is ERC165MappingImplementation, Simpson {
|
||||
constructor() public {
|
||||
supportedInterfaces[this.is2D.selector ^ this.skinColor.selector] = true;
|
||||
}
|
||||
|
||||
function is2D() external override returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function skinColor() external override returns (string memory) {
|
||||
return "yellow";
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// supportsInterface(bytes4): left(0x01ffc9a0) -> false
|
||||
// supportsInterface(bytes4): left(0x01ffc9a7) -> true
|
||||
// supportsInterface(bytes4): left(0x73b6b492) -> true
|
||||
// supportsInterface(bytes4): left(0x70b6b492) -> false
|
||||
@@ -0,0 +1,47 @@
|
||||
interface ERC165 {
|
||||
/// @notice Query if a contract implements an interface
|
||||
/// @param interfaceID The interface identifier, as specified in ERC-165
|
||||
/// @dev Interface identification is specified in ERC-165. This function
|
||||
/// uses less than 30,000 gas.
|
||||
/// @return `true` if the contract implements `interfaceID` and
|
||||
/// `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
||||
|
||||
contract ERC165MappingImplementation is ERC165 {
|
||||
/// @dev You must not set element 0xffffffff to true
|
||||
mapping(bytes4 => bool) internal supportedInterfaces;
|
||||
|
||||
constructor() internal {
|
||||
supportedInterfaces[this.supportsInterface.selector] = true;
|
||||
}
|
||||
|
||||
function supportsInterface(bytes4 interfaceID) external view override returns (bool) {
|
||||
return supportedInterfaces[interfaceID];
|
||||
}
|
||||
}
|
||||
|
||||
interface Simpson {
|
||||
function is2D() external returns (bool);
|
||||
function skinColor() external returns (string memory);
|
||||
}
|
||||
|
||||
contract Lisa is ERC165MappingImplementation, Simpson {
|
||||
constructor() public {
|
||||
supportedInterfaces[type(Simpson).interfaceId] = true;
|
||||
}
|
||||
|
||||
function is2D() external override returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function skinColor() external override returns (string memory) {
|
||||
return "yellow";
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// supportsInterface(bytes4): left(0x01ffc9a0) -> false
|
||||
// supportsInterface(bytes4): left(0x01ffc9a7) -> true
|
||||
// supportsInterface(bytes4): left(0x73b6b492) -> true
|
||||
// supportsInterface(bytes4): left(0x70b6b492) -> false
|
||||
@@ -33,6 +33,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// convertParent() -> 1
|
||||
// convertSubA() -> 1, 2
|
||||
|
||||
@@ -19,6 +19,8 @@ contract D {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1
|
||||
// g() -> 5
|
||||
|
||||
+2
@@ -21,5 +21,7 @@ contract B {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 42
|
||||
|
||||
+2
@@ -21,5 +21,7 @@ contract B {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 42
|
||||
|
||||
@@ -15,5 +15,7 @@ contract B {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 1
|
||||
|
||||
@@ -17,5 +17,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
|
||||
@@ -22,5 +22,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 2
|
||||
|
||||
@@ -6,6 +6,8 @@ contract C {
|
||||
return L.f(v);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g(uint256): 1 -> 1
|
||||
// g(uint256): 2 -> 4
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
abstract contract A {
|
||||
function f() public mod returns (bool r) {
|
||||
return true;
|
||||
}
|
||||
|
||||
modifier mod virtual;
|
||||
}
|
||||
|
||||
|
||||
contract C is A {
|
||||
modifier mod override {
|
||||
if (false) _;
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// f() -> false
|
||||
@@ -0,0 +1,14 @@
|
||||
contract A {
|
||||
uint public x = 0;
|
||||
uint y = f();
|
||||
function f() public returns (uint256) {
|
||||
++x;
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x() -> 1
|
||||
@@ -0,0 +1,18 @@
|
||||
contract A {
|
||||
uint public x = 0;
|
||||
uint y = f();
|
||||
function f() public returns (uint256) {
|
||||
++x;
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
contract B is A {
|
||||
uint public z;
|
||||
constructor() public {
|
||||
z = x;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// z() -> 1
|
||||
@@ -0,0 +1,29 @@
|
||||
contract A {
|
||||
uint public a = 42;
|
||||
uint public b;
|
||||
uint public c;
|
||||
constructor(uint x) public {
|
||||
b = a;
|
||||
a = x;
|
||||
}
|
||||
function f(uint x) public returns (uint256) { c = x * 3; return 23; }
|
||||
}
|
||||
contract B is A {
|
||||
uint public d = f(a);
|
||||
uint public e = b;
|
||||
uint public b_a;
|
||||
uint public b_b;
|
||||
uint public b_c;
|
||||
constructor() public A(17) { b_a = a; b_b = b; b_c = c; }
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// a() -> 17
|
||||
// b() -> 42
|
||||
// c() -> 51
|
||||
// b_a() -> 17
|
||||
// b_b() -> 42
|
||||
// b_c() -> 51
|
||||
// d() -> 23
|
||||
// e() -> 42
|
||||
@@ -16,5 +16,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor() ->
|
||||
|
||||
@@ -23,6 +23,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 9, 7
|
||||
// t2() -> 9
|
||||
|
||||
@@ -15,6 +15,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
||||
// g() -> true
|
||||
|
||||
@@ -15,6 +15,8 @@ contract D {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(), 27 wei ->
|
||||
// f() -> 27
|
||||
|
||||
@@ -32,6 +32,7 @@ contract D {
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// EVMVersion: >=byzantium
|
||||
// ----
|
||||
// f() -> 0x1 # This should work, next should throw #
|
||||
|
||||
@@ -34,6 +34,8 @@ contract D {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 3
|
||||
// g() -> 8
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function f(bytes calldata x) external pure {
|
||||
x[:18726387213];
|
||||
x[18726387213:];
|
||||
x[18726387213:111111111111111111];
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (94-109): Assertion checker does not yet implement this expression.
|
||||
// Warning: (113-128): Assertion checker does not yet implement this expression.
|
||||
// Warning: (132-165): Assertion checker does not yet implement this expression.
|
||||
@@ -0,0 +1,13 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function f(bytes calldata x) external pure {
|
||||
bytes(x[:18726387213]);
|
||||
bytes(x[18726387213:]);
|
||||
bytes(x[18726387213:111111111111111111]);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (100-115): Assertion checker does not yet implement this expression.
|
||||
// Warning: (126-141): Assertion checker does not yet implement this expression.
|
||||
// Warning: (152-185): Assertion checker does not yet implement this expression.
|
||||
@@ -0,0 +1,14 @@
|
||||
abstract contract A { modifier mod(uint a) virtual;}
|
||||
contract B is A { modifier mod(uint a) override { _; } }
|
||||
|
||||
abstract contract C {
|
||||
modifier m virtual;
|
||||
function f() m public {
|
||||
|
||||
}
|
||||
}
|
||||
contract D is C {
|
||||
modifier m override {
|
||||
_;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
contract A {modifier m virtual;}
|
||||
|
||||
abstract contract B {modifier m virtual;}
|
||||
contract C is B { }
|
||||
|
||||
abstract contract D {modifier m;}
|
||||
// ----
|
||||
// TypeError: (0-32): Contract "A" should be marked as abstract.
|
||||
// TypeError: (76-95): Contract "C" should be marked as abstract.
|
||||
// TypeError: (118-129): Modifiers without implementation must be marked virtual.
|
||||
@@ -0,0 +1,31 @@
|
||||
abstract contract A {
|
||||
function foo() public virtual;
|
||||
function foo(uint x) virtual public returns(uint);
|
||||
modifier mod() virtual;
|
||||
}
|
||||
|
||||
contract B is A {
|
||||
function foo(uint x) override public returns(uint) {return x;}
|
||||
modifier mod() override { _; }
|
||||
}
|
||||
|
||||
contract C is A {
|
||||
function foo() public override {}
|
||||
modifier mod() override { _; }
|
||||
}
|
||||
|
||||
contract D is A {
|
||||
function foo() public override {}
|
||||
function foo(uint x) override public returns(uint) {return x;}
|
||||
}
|
||||
|
||||
/* No errors */
|
||||
contract E is A {
|
||||
function foo() public override {}
|
||||
function foo(uint x) override public returns(uint) {return x;}
|
||||
modifier mod() override { _;}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (137-254): Contract "B" should be marked as abstract.
|
||||
// TypeError: (256-344): Contract "C" should be marked as abstract.
|
||||
// TypeError: (346-466): Contract "D" should be marked as abstract.
|
||||
@@ -0,0 +1,29 @@
|
||||
contract C {
|
||||
function f0() public { (()) = 2; }
|
||||
|
||||
function f1() public pure { (()) = (); }
|
||||
|
||||
//#8711
|
||||
function f2() internal pure returns (uint, uint) { return () = f2(); }
|
||||
|
||||
//#8277
|
||||
function f3()public{return()=();}
|
||||
|
||||
//#8277
|
||||
function f4 ( bytes32 hash , uint8 v , bytes32 r , bytes32 s , uint blockExpired , bytes32 salt ) public returns ( address ) {
|
||||
require ( ( ( ) ) |= keccak256 ( abi . encodePacked ( blockExpired , salt ) ) ) ;
|
||||
return ecrecover ( hash , v , r , s ) ;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (41-43): Empty tuple on the left hand side.
|
||||
// TypeError: (47-48): Type int_const 2 is not implicitly convertible to expected type tuple().
|
||||
// TypeError: (86-88): Empty tuple on the left hand side.
|
||||
// TypeError: (173-175): Empty tuple on the left hand side.
|
||||
// TypeError: (178-182): Type tuple(uint256,uint256) is not implicitly convertible to expected type tuple().
|
||||
// TypeError: (166-182): Different number of arguments in return statement than in returns declaration.
|
||||
// TypeError: (229-231): Empty tuple on the left hand side.
|
||||
// TypeError: (401-404): Empty tuple on the left hand side.
|
||||
// TypeError: (399-466): Compound assignment is not allowed for tuple types.
|
||||
// TypeError: (410-466): Type bytes32 is not implicitly convertible to expected type tuple().
|
||||
// TypeError: (389-396): No matching declaration found after argument-dependent lookup.
|
||||
Reference in New Issue
Block a user