diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 473114961..314d4283e 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1551,26 +1551,6 @@ BOOST_AUTO_TEST_CASE(generic_staticcall) } } -BOOST_AUTO_TEST_CASE(library_call_in_homestead) -{ - char const* sourceCode = R"( - library Lib { function m() public returns (address) { return msg.sender; } } - contract Test { - address public sender; - function f() public { - sender = Lib.m(); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("sender()"), encodeArgs(m_sender)); - ) -} - BOOST_AUTO_TEST_CASE(library_call_protection) { // This tests code that reverts a call if it is a direct call to a library @@ -1626,38 +1606,6 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) ); } -BOOST_AUTO_TEST_CASE(call_forward_bytes) -{ - char const* sourceCode = R"( - contract receiver { - uint public received; - function recv(uint x) public { received += x + 1; } - fallback() external { received = 0x80; } - } - contract sender { - constructor() { rec = new receiver(); } - fallback() external { savedData = msg.data; } - function forward() public returns (bool) { address(rec).call(savedData); return true; } - function clear() public returns (bool) { delete savedData; return true; } - function val() public returns (uint) { return rec.received(); } - receiver rec; - bytes savedData; - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN(); - compileAndRun(sourceCode, 0, "sender"); - ABI_CHECK(callContractFunction("recv(uint256)", 7), bytes()); - ABI_CHECK(callContractFunction("val()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("forward()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("clear()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("forward()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80)); - ); -} - BOOST_AUTO_TEST_CASE(call_forward_bytes_length) { char const* sourceCode = R"( @@ -2576,254 +2524,6 @@ BOOST_AUTO_TEST_CASE(library_function_external) ) } -BOOST_AUTO_TEST_CASE(library_stray_values) -{ - char const* sourceCode = R"( - library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } } - contract Test { - function f(uint x) public returns (uint) { - Lib; - Lib.m; - return x + 9; - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(42))); - ) -} - -BOOST_AUTO_TEST_CASE(internal_types_in_library) -{ - char const* sourceCode = R"( - library Lib { - function find(uint16[] storage _haystack, uint16 _needle) public view returns (uint) - { - for (uint i = 0; i < _haystack.length; ++i) - if (_haystack[i] == _needle) - return i; - return type(uint).max; - } - } - contract Test { - mapping(string => uint16[]) data; - function f() public returns (uint a, uint b) - { - while (data["abc"].length < 20) - data["abc"].push(); - data["abc"][4] = 9; - data["abc"][17] = 3; - a = Lib.find(data["abc"], 9); - b = Lib.find(data["abc"], 3); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(4), u256(17))); - ) -} - -BOOST_AUTO_TEST_CASE(mapping_arguments_in_library) -{ - char const* sourceCode = R"( - library Lib { - function set(mapping(uint => uint) storage m, uint key, uint value) internal - { - m[key] = value; - } - function get(mapping(uint => uint) storage m, uint key) internal view returns (uint) - { - return m[key]; - } - } - contract Test { - mapping(uint => uint) m; - function set(uint256 key, uint256 value) public returns (uint) - { - uint oldValue = Lib.get(m, key); - Lib.set(m, key, value); - return oldValue; - } - function get(uint256 key) public view returns (uint) { - return Lib.get(m, key); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(1), u256(42)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(2), u256(84)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(21), u256(7)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(uint256)", u256(1)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(uint256)", u256(2)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("get(uint256)", u256(21)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(1), u256(21)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(2), u256(42)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(21), u256(14)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("get(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(uint256)", u256(1)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("get(uint256)", u256(2)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(uint256)", u256(21)), encodeArgs(u256(14))); - ) -} - -BOOST_AUTO_TEST_CASE(mapping_returns_in_library) -{ - char const* sourceCode = R"( - library Lib { - function choose_mapping(mapping(uint => uint) storage a, mapping(uint => uint) storage b, bool c) internal pure returns(mapping(uint=>uint) storage) - { - return c ? a : b; - } - } - contract Test { - mapping(uint => uint) a; - mapping(uint => uint) b; - function set(bool choice, uint256 key, uint256 value) public returns (uint) - { - mapping(uint => uint) storage m = Lib.choose_mapping(a, b, choice); - uint oldValue = m[key]; - m[key] = value; - return oldValue; - } - function get(bool choice, uint256 key) public view returns (uint) { - return Lib.choose_mapping(a, b, choice)[key]; - } - function get_a(uint256 key) public view returns (uint) { - return a[key]; - } - function get_b(uint256 key) public view returns (uint) { - return b[key]; - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(1), u256(42)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(2), u256(84)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(21), u256(7)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(1), u256(10)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(2), u256(11)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(21), u256(12)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(1)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(2)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(21)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(1)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(2)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(21)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(1)), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(2)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(21)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(1)), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(2)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(21)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(1), u256(21)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(2), u256(42)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(21), u256(14)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(1), u256(30)), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(2), u256(31)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(21), u256(32)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(1)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(2)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(21)), encodeArgs(u256(14))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(1)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(2)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(21)), encodeArgs(u256(14))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(1)), encodeArgs(u256(30))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(2)), encodeArgs(u256(31))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(21)), encodeArgs(u256(32))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(1)), encodeArgs(u256(30))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(2)), encodeArgs(u256(31))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(21)), encodeArgs(u256(32))); - ) -} - -BOOST_AUTO_TEST_CASE(mapping_returns_in_library_named) -{ - char const* sourceCode = R"( - library Lib { - function f(mapping(uint => uint) storage a, mapping(uint => uint) storage b) internal returns(mapping(uint=>uint) storage r) - { - r = a; - r[1] = 42; - r = b; - r[1] = 21; - } - } - contract Test { - mapping(uint => uint) a; - mapping(uint => uint) b; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.f(a, b)[2] = 84; - return (a[0], a[1], a[2], b[0], b[1], b[2]); - } - function g() public returns (uint, uint, uint, uint, uint, uint) - { - mapping(uint => uint) storage m = Lib.f(a, b); - m[2] = 17; - return (a[0], a[1], a[2], b[0], b[1], b[2]); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(84))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(17))); - ) -} - -BOOST_AUTO_TEST_CASE(using_library_mappings_public) -{ - char const* sourceCode = R"( - library Lib { - function set(mapping(uint => uint) storage m, uint key, uint value) public - { - m[key] = value; - } - } - contract Test { - mapping(uint => uint) m1; - mapping(uint => uint) m2; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.set(m1, 0, 1); - Lib.set(m1, 2, 42); - Lib.set(m2, 0, 23); - Lib.set(m2, 2, 99); - return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); - ) -} - BOOST_AUTO_TEST_CASE(using_library_mappings_external) { char const* libSourceCode = R"( @@ -2860,65 +2560,6 @@ BOOST_AUTO_TEST_CASE(using_library_mappings_external) } } -BOOST_AUTO_TEST_CASE(using_library_mappings_return) -{ - char const* sourceCode = R"( - library Lib { - function choose(mapping(uint => mapping(uint => uint)) storage m, uint key) external returns (mapping(uint => uint) storage) { - return m[key]; - } - } - contract Test { - mapping(uint => mapping(uint => uint)) m; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.choose(m, 0)[0] = 1; - Lib.choose(m, 0)[2] = 42; - Lib.choose(m, 1)[0] = 23; - Lib.choose(m, 1)[2] = 99; - return (m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); - ) -} - -BOOST_AUTO_TEST_CASE(using_library_structs) -{ - char const* sourceCode = R"( - library Lib { - struct Data { uint a; uint[] b; } - function set(Data storage _s) public - { - _s.a = 7; - while (_s.b.length < 20) - _s.b.push(); - _s.b[19] = 8; - } - } - contract Test { - mapping(string => Lib.Data) data; - function f() public returns (uint a, uint b) - { - Lib.set(data["abc"]); - a = data["abc"].a; - b = data["abc"].b[19]; - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{":Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), u256(8))); - ) -} - BOOST_AUTO_TEST_CASE(short_strings) { // This test verifies that the byte array encoding that combines length and data works @@ -3114,146 +2755,6 @@ BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) } } -BOOST_AUTO_TEST_CASE(using_for_function_on_struct) -{ - char const* sourceCode = R"( - library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 3; - return x.mul(a); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(3 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(3 * 7))); - ) -} - -BOOST_AUTO_TEST_CASE(using_for_overload) -{ - char const* sourceCode = R"( - library D { - struct s { uint a; } - function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } - function mul(s storage self, bytes32 x) public returns (bytes32) { } - } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 6; - return x.mul(a); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); - ) -} - -BOOST_AUTO_TEST_CASE(using_for_by_name) -{ - char const* sourceCode = R"( - library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 6; - return x.mul({x: a}); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); - ) -} - -BOOST_AUTO_TEST_CASE(bound_function_in_function) -{ - char const* sourceCode = R"( - library L { - function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); } - } - contract C { - using L for *; - function f() public returns (uint) { - return t.g(); - } - function t() public pure returns (uint) { return 7; } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "L"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":L", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ) -} - -BOOST_AUTO_TEST_CASE(bound_function_in_var) -{ - char const* sourceCode = R"( - library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 6; - return (x.mul)({x: a}); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); - ) -} - -BOOST_AUTO_TEST_CASE(bound_function_to_string) -{ - char const* sourceCode = R"( - library D { function length(string memory self) public returns (uint) { return bytes(self).length; } } - contract C { - using D for string; - string x; - function f() public returns (uint) { - x = "abc"; - return x.length(); - } - function g() public returns (uint) { - string memory s = "abc"; - return s.length(); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(3))); - ) -} - BOOST_AUTO_TEST_CASE(inline_long_string_return) { char const* sourceCode = R"( @@ -3406,26 +2907,6 @@ BOOST_AUTO_TEST_CASE(payable_function) BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); } -BOOST_AUTO_TEST_CASE(payable_function_calls_library) -{ - char const* sourceCode = R"( - library L { - function f() public returns (uint) { return 7; } - } - contract C { - function f() public payable returns (uint) { - return L.f(); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "L"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{":L", m_contractAddress}}); - ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs(u256(7))); - ) -} - BOOST_AUTO_TEST_CASE(non_payable_throw) { char const* sourceCode = R"( diff --git a/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol b/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol new file mode 100644 index 000000000..3583a752d --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/copying_bytes_multiassign.sol @@ -0,0 +1,33 @@ +contract receiver { + uint public received; + function recv(uint x) public { received += x + 1; } + fallback() external { received = 0x80; } +} +contract sender { + constructor() { rec = new receiver(); } + fallback() external { savedData1 = savedData2 = msg.data; } + function forward(bool selector) public returns (bool) { + if (selector) { address(rec).call(savedData1); delete savedData1; } + else { address(rec).call(savedData2); delete savedData2; } + return true; + } + function val() public returns (uint) { return rec.received(); } + receiver rec; + bytes savedData1; + bytes savedData2; +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// (): 7 -> +// gas irOptimized: 110941 +// gas legacy: 111082 +// gas legacyOptimized: 111027 +// val() -> 0 +// forward(bool): true -> true +// val() -> 0x80 +// forward(bool): false -> true +// val() -> 0x80 +// forward(bool): true -> true +// val() -> 0x80 diff --git a/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol b/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol new file mode 100644 index 000000000..87067b77b --- /dev/null +++ b/test/libsolidity/semanticTests/calldata/copy_from_calldata_removes_bytes_data.sol @@ -0,0 +1,19 @@ +contract c { + function set() public returns (bool) { data = msg.data; return true; } + function checkIfDataIsEmpty() public returns (bool) { return data.length == 0; } + function sendMessage() public returns (bool, bytes memory) { bytes memory emptyData; return address(this).call(emptyData);} + fallback() external { data = msg.data; } + bytes data; +} +// ==== +// EVMVersion: >=byzantium +// compileToEwasm: false +// compileViaYul: also +// ---- +// (): 1, 2, 3, 4, 5 -> +// gas irOptimized: 155178 +// gas legacy: 155254 +// gas legacyOptimized: 155217 +// checkIfDataIsEmpty() -> false +// sendMessage() -> true, 0x40, 0 +// checkIfDataIsEmpty() -> true diff --git a/test/libsolidity/semanticTests/enums/enum_referencing.sol b/test/libsolidity/semanticTests/enums/enum_referencing.sol new file mode 100644 index 000000000..537c05182 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/enum_referencing.sol @@ -0,0 +1,41 @@ +interface I { + enum Direction { A, B, Left, Right } +} +library L { + enum Direction { Left, Right } + function f() public pure returns (Direction) { + return Direction.Right; + } + function g() public pure returns (I.Direction) { + return I.Direction.Right; + } +} +contract C is I { + function f() public pure returns (Direction) { + return Direction.Right; + } + function g() public pure returns (I.Direction) { + return I.Direction.Right; + } + function h() public pure returns (L.Direction) { + return L.Direction.Right; + } + function x() public pure returns (L.Direction) { + return L.f(); + } + function y() public pure returns (I.Direction) { + return L.g(); + } +} +// ==== +// compileViaYul: also +// compileToEwasm: false +// ---- +// library: L +// f() -> 3 +// g() -> 3 +// f() -> 3 +// g() -> 3 +// h() -> 1 +// x() -> 1 +// y() -> 3 diff --git a/test/libsolidity/semanticTests/fallback/call_forward_bytes.sol b/test/libsolidity/semanticTests/fallback/call_forward_bytes.sol new file mode 100644 index 000000000..39122e757 --- /dev/null +++ b/test/libsolidity/semanticTests/fallback/call_forward_bytes.sol @@ -0,0 +1,27 @@ +contract receiver { + uint256 public received; + function recv(uint256 x) public { received += x + 1; } + fallback() external { received = 0x80; } +} +contract sender { + constructor() { rec = new receiver();} + fallback() external { savedData = msg.data; } + function forward() public returns (bool) { address(rec).call(savedData); return true; } + function clear() public returns (bool) { delete savedData; return true; } + function val() public returns (uint) { return rec.received(); } + receiver rec; + bytes savedData; +} +// ==== +// allowNonExistingFunctions: true +// compileToEwasm: false +// compileViaYul: also +// ---- +// recv(uint256): 7 -> +// val() -> 0 +// forward() -> true +// val() -> 8 +// clear() -> true +// val() -> 8 +// forward() -> true +// val() -> 0x80 diff --git a/test/libsolidity/semanticTests/functionCall/bound_function_in_function.sol b/test/libsolidity/semanticTests/functionCall/bound_function_in_function.sol new file mode 100644 index 000000000..983de5e3c --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/bound_function_in_function.sol @@ -0,0 +1,16 @@ +library L { + function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); } +} +contract C { + using L for *; + function f() public returns (uint) { + return t.g(); + } + function t() public pure returns (uint) { return 7; } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: L +// f() -> 7 diff --git a/test/libsolidity/semanticTests/functionCall/bound_function_in_var.sol b/test/libsolidity/semanticTests/functionCall/bound_function_in_var.sol new file mode 100644 index 000000000..ad8024127 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/bound_function_in_var.sol @@ -0,0 +1,16 @@ +library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } +contract C { + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 6; + return (x.mul)({x: a}); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: D +// f(uint256): 7 -> 0x2a +// x() -> 0x2a diff --git a/test/libsolidity/semanticTests/functionCall/bound_function_to_string.sol b/test/libsolidity/semanticTests/functionCall/bound_function_to_string.sol new file mode 100644 index 000000000..376768b86 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/bound_function_to_string.sol @@ -0,0 +1,20 @@ +library D { function length(string memory self) public returns (uint) { return bytes(self).length; } } +contract C { + using D for string; + string x; + function f() public returns (uint) { + x = "abc"; + return x.length(); + } + function g() public returns (uint) { + string memory s = "abc"; + return s.length(); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: D +// f() -> 3 +// g() -> 3 diff --git a/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol b/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol new file mode 100644 index 000000000..6b13ee09c --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/internal_types_in_library.sol @@ -0,0 +1,30 @@ +library Lib { + function find(uint16[] storage _haystack, uint16 _needle) public view returns (uint) + { + for (uint i = 0; i < _haystack.length; ++i) + if (_haystack[i] == _needle) + return i; + return type(uint).max; + } +} +contract Test { + mapping(string => uint16[]) data; + function f() public returns (uint a, uint b) + { + while (data["abc"].length < 20) + data["abc"].push(); + data["abc"][4] = 9; + data["abc"][17] = 3; + a = Lib.find(data["abc"], 9); + b = Lib.find(data["abc"], 3); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// f() -> 4, 0x11 +// gas irOptimized: 115822 +// gas legacy: 135952 +// gas legacyOptimized: 119643 diff --git a/test/libsolidity/semanticTests/libraries/library_call_in_homestead.sol b/test/libsolidity/semanticTests/libraries/library_call_in_homestead.sol new file mode 100644 index 000000000..6841221f4 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/library_call_in_homestead.sol @@ -0,0 +1,15 @@ +library Lib { function m() public returns (address) { return msg.sender; } } +contract Test { + address public sender; + function f() public { + sender = Lib.m(); + } +} +// ==== +// compileViaYul: also +// compileToEwasm: false +// EVMVersion: >=homestead +// ---- +// library: Lib +// f() -> +// sender() -> 0x1212121212121212121212121212120000000012 diff --git a/test/libsolidity/semanticTests/libraries/library_stray_values.sol b/test/libsolidity/semanticTests/libraries/library_stray_values.sol new file mode 100644 index 000000000..1692b018a --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/library_stray_values.sol @@ -0,0 +1,14 @@ +library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } } +contract Test { + function f(uint x) public returns (uint) { + Lib; + Lib.m; + return x + 9; + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// f(uint256): 33 -> 0x2a diff --git a/test/libsolidity/semanticTests/libraries/mapping_arguments_in_library.sol b/test/libsolidity/semanticTests/libraries/mapping_arguments_in_library.sol new file mode 100644 index 000000000..06cfd6e1a --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/mapping_arguments_in_library.sol @@ -0,0 +1,41 @@ +library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) internal + { + m[key] = value; + } + function get(mapping(uint => uint) storage m, uint key) internal view returns (uint) + { + return m[key]; + } +} +contract Test { + mapping(uint => uint) m; + function set(uint256 key, uint256 value) public returns (uint) + { + uint oldValue = Lib.get(m, key); + Lib.set(m, key, value); + return oldValue; + } + function get(uint256 key) public view returns (uint) { + return Lib.get(m, key); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// set(uint256,uint256): 1, 42 -> 0 +// set(uint256,uint256): 2, 84 -> 0 +// set(uint256,uint256): 21, 7 -> 0 +// get(uint256): 0 -> 0 +// get(uint256): 1 -> 0x2a +// get(uint256): 2 -> 0x54 +// get(uint256): 21 -> 7 +// set(uint256,uint256): 1, 21 -> 0x2a +// set(uint256,uint256): 2, 42 -> 0x54 +// set(uint256,uint256): 21, 14 -> 7 +// get(uint256): 0 -> 0 +// get(uint256): 1 -> 0x15 +// get(uint256): 2 -> 0x2a +// get(uint256): 21 -> 14 diff --git a/test/libsolidity/semanticTests/libraries/mapping_returns_in_library.sol b/test/libsolidity/semanticTests/libraries/mapping_returns_in_library.sol new file mode 100644 index 000000000..dd2b2953f --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/mapping_returns_in_library.sol @@ -0,0 +1,75 @@ +library Lib { + function choose_mapping(mapping(uint => uint) storage a, mapping(uint => uint) storage b, bool c) internal pure returns(mapping(uint=>uint) storage) + { + return c ? a : b; + } +} +contract Test { + mapping(uint => uint) a; + mapping(uint => uint) b; + function set(bool choice, uint256 key, uint256 value) public returns (uint) + { + mapping(uint => uint) storage m = Lib.choose_mapping(a, b, choice); + uint oldValue = m[key]; + m[key] = value; + return oldValue; + } + function get(bool choice, uint256 key) public view returns (uint) { + return Lib.choose_mapping(a, b, choice)[key]; + } + function get_a(uint256 key) public view returns (uint) { + return a[key]; + } + function get_b(uint256 key) public view returns (uint) { + return b[key]; + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// set(bool,uint256,uint256): true, 1, 42 -> 0 +// set(bool,uint256,uint256): true, 2, 84 -> 0 +// set(bool,uint256,uint256): true, 21, 7 -> 0 +// set(bool,uint256,uint256): false, 1, 10 -> 0 +// set(bool,uint256,uint256): false, 2, 11 -> 0 +// set(bool,uint256,uint256): false, 21, 12 -> 0 +// get(bool,uint256): true, 0 -> 0 +// get(bool,uint256): true, 1 -> 0x2a +// get(bool,uint256): true, 2 -> 0x54 +// get(bool,uint256): true, 21 -> 7 +// get_a(uint256): 0 -> 0 +// get_a(uint256): 1 -> 0x2a +// get_a(uint256): 2 -> 0x54 +// get_a(uint256): 21 -> 7 +// get(bool,uint256): false, 0 -> 0 +// get(bool,uint256): false, 1 -> 10 +// get(bool,uint256): false, 2 -> 11 +// get(bool,uint256): false, 21 -> 12 +// get_b(uint256): 0 -> 0 +// get_b(uint256): 1 -> 10 +// get_b(uint256): 2 -> 11 +// get_b(uint256): 21 -> 12 +// set(bool,uint256,uint256): true, 1, 21 -> 0x2a +// set(bool,uint256,uint256): true, 2, 42 -> 0x54 +// set(bool,uint256,uint256): true, 21, 14 -> 7 +// set(bool,uint256,uint256): false, 1, 30 -> 10 +// set(bool,uint256,uint256): false, 2, 31 -> 11 +// set(bool,uint256,uint256): false, 21, 32 -> 12 +// get_a(uint256): 0 -> 0 +// get_a(uint256): 1 -> 0x15 +// get_a(uint256): 2 -> 0x2a +// get_a(uint256): 21 -> 14 +// get(bool,uint256): true, 0 -> 0 +// get(bool,uint256): true, 1 -> 0x15 +// get(bool,uint256): true, 2 -> 0x2a +// get(bool,uint256): true, 21 -> 14 +// get_b(uint256): 0 -> 0 +// get_b(uint256): 1 -> 0x1e +// get_b(uint256): 2 -> 0x1f +// get_b(uint256): 21 -> 0x20 +// get(bool,uint256): false, 0 -> 0 +// get(bool,uint256): false, 1 -> 0x1e +// get(bool,uint256): false, 2 -> 0x1f +// get(bool,uint256): false, 21 -> 0x20 diff --git a/test/libsolidity/semanticTests/libraries/mapping_returns_in_library_named.sol b/test/libsolidity/semanticTests/libraries/mapping_returns_in_library_named.sol new file mode 100644 index 000000000..23f851279 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/mapping_returns_in_library_named.sol @@ -0,0 +1,31 @@ +library Lib { + function f(mapping(uint => uint) storage a, mapping(uint => uint) storage b) internal returns(mapping(uint=>uint) storage r) + { + r = a; + r[1] = 42; + r = b; + r[1] = 21; + } +} +contract Test { + mapping(uint => uint) a; + mapping(uint => uint) b; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.f(a, b)[2] = 84; + return (a[0], a[1], a[2], b[0], b[1], b[2]); + } + function g() public returns (uint, uint, uint, uint, uint, uint) + { + mapping(uint => uint) storage m = Lib.f(a, b); + m[2] = 17; + return (a[0], a[1], a[2], b[0], b[1], b[2]); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// f() -> 0, 0x2a, 0, 0, 0x15, 0x54 +// g() -> 0, 0x2a, 0, 0, 0x15, 0x11 diff --git a/test/libsolidity/semanticTests/libraries/payable_function_calls_library.sol b/test/libsolidity/semanticTests/libraries/payable_function_calls_library.sol new file mode 100644 index 000000000..6b0488f06 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/payable_function_calls_library.sol @@ -0,0 +1,14 @@ +library L { + function f() public returns (uint) { return 7; } +} +contract C { + function f() public payable returns (uint) { + return L.f(); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: L +// f(): 27 -> 7 diff --git a/test/libsolidity/semanticTests/libraries/using_for_by_name.sol b/test/libsolidity/semanticTests/libraries/using_for_by_name.sol new file mode 100644 index 000000000..8a84c8aaa --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_for_by_name.sol @@ -0,0 +1,16 @@ +library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } +contract C { + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 6; + return x.mul({x: a}); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: D +// f(uint256): 7 -> 0x2a +// x() -> 0x2a diff --git a/test/libsolidity/semanticTests/libraries/using_for_overload.sol b/test/libsolidity/semanticTests/libraries/using_for_overload.sol new file mode 100644 index 000000000..54cfe0ce1 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_for_overload.sol @@ -0,0 +1,20 @@ +library D { + struct s { uint a; } + function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } + function mul(s storage self, bytes32 x) public returns (bytes32) { } +} +contract C { + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 6; + return x.mul(a); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: D +// f(uint256): 7 -> 0x2a +// x() -> 0x2a diff --git a/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol b/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol new file mode 100644 index 000000000..d85f90694 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_library_mappings_public.sol @@ -0,0 +1,27 @@ +library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) public + { + m[key] = value; + } +} +contract Test { + mapping(uint => uint) m1; + mapping(uint => uint) m2; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.set(m1, 0, 1); + Lib.set(m1, 2, 42); + Lib.set(m2, 0, 23); + Lib.set(m2, 2, 99); + return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// f() -> 1, 0, 0x2a, 0x17, 0, 0x63 +// gas irOptimized: 119757 +// gas legacy: 124793 +// gas legacyOptimized: 119694 diff --git a/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol b/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol new file mode 100644 index 000000000..9192fdfe3 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_library_mappings_return.sol @@ -0,0 +1,25 @@ +library Lib { + function choose(mapping(uint => mapping(uint => uint)) storage m, uint key) external returns (mapping(uint => uint) storage) { + return m[key]; + } +} +contract Test { + mapping(uint => mapping(uint => uint)) m; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.choose(m, 0)[0] = 1; + Lib.choose(m, 0)[2] = 42; + Lib.choose(m, 1)[0] = 23; + Lib.choose(m, 1)[2] = 99; + return (m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// f() -> 1, 0, 0x2a, 0x17, 0, 0x63 +// gas irOptimized: 120471 +// gas legacy: 125245 +// gas legacyOptimized: 120153 diff --git a/test/libsolidity/semanticTests/libraries/using_library_structs.sol b/test/libsolidity/semanticTests/libraries/using_library_structs.sol new file mode 100644 index 000000000..4348c377c --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_library_structs.sol @@ -0,0 +1,27 @@ +library Lib { + struct Data { uint a; uint[] b; } + function set(Data storage _s) public + { + _s.a = 7; + while (_s.b.length < 20) + _s.b.push(); + _s.b[19] = 8; + } +} +contract Test { + mapping(string => Lib.Data) data; + function f() public returns (uint a, uint b) + { + Lib.set(data["abc"]); + a = data["abc"].a; + b = data["abc"].b[19]; + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: Lib +// f() -> 7, 8 +// gas irOptimized: 101869 +// gas legacy: 101504 diff --git a/test/libsolidity/semanticTests/structs/struct_referencing.sol b/test/libsolidity/semanticTests/structs/struct_referencing.sol new file mode 100644 index 000000000..af2357a23 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_referencing.sol @@ -0,0 +1,61 @@ +pragma abicoder v2; +interface I { + struct S { uint a; } +} + +library L { + struct S { uint b; uint a; } + function f() public pure returns (S memory) { + S memory s; + s.a = 3; + return s; + } + function g() public pure returns (I.S memory) { + I.S memory s; + s.a = 4; + return s; + } + // argument-dependant lookup tests + function a(I.S memory) public pure returns (uint) { return 1; } + function a(S memory) public pure returns (uint) { return 2; } +} + +contract C is I { + function f() public pure returns (S memory) { + S memory s; + s.a = 1; + return 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 memory) { + L.S memory s; + s.a = 5; + return s; + } + function x() public pure returns (L.S memory) { + return L.f(); + } + function y() public pure returns (I.S memory) { + return L.g(); + } + function a1() public pure returns (uint) { S memory s; return L.a(s); } + function a2() public pure returns (uint) { L.S memory s; return L.a(s); } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: L +// f() -> 1 +// g() -> 2 +// f() -> 1 +// g() -> 2 +// h() -> 0, 5 +// x() -> 0, 3 +// y() -> 4 +// a1() -> 1 +// a2() -> 2 diff --git a/test/libsolidity/semanticTests/structs/using_for_function_on_struct.sol b/test/libsolidity/semanticTests/structs/using_for_function_on_struct.sol new file mode 100644 index 000000000..347aeb595 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/using_for_function_on_struct.sol @@ -0,0 +1,16 @@ +library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } +contract C { + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 3; + return x.mul(a); + } +} +// ==== +// compileToEwasm: false +// compileViaYul: also +// ---- +// library: D +// f(uint256): 7 -> 0x15 +// x() -> 0x15