aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md2
-rw-r--r--docs/types.rst4
-rw-r--r--libsolidity/ast/Types.cpp9
-rw-r--r--libsolidity/ast/Types.h1
-rw-r--r--libsolidity/codegen/ArrayUtils.cpp79
-rw-r--r--libsolidity/codegen/ArrayUtils.h5
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp21
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp286
-rw-r--r--test/libsolidity/syntaxTests/array/array_pop.sol7
-rw-r--r--test/libsolidity/syntaxTests/array/array_pop_arg.sol8
-rw-r--r--test/libsolidity/syntaxTests/array/bytes_pop.sol7
-rw-r--r--test/libsolidity/syntaxTests/array/dynamic_memory_array_pop.sol8
-rw-r--r--test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol (renamed from test/libsolidity/syntaxTests/arrayLength/array_length_cannot_be_constant_function_parameter.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/can_be_constant_in_function.sol (renamed from test/libsolidity/syntaxTests/arrayLength/can_be_constant_in_function.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/can_be_constant_in_struct.sol (renamed from test/libsolidity/syntaxTests/arrayLength/can_be_constant_in_struct.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/can_be_recursive_constant.sol (renamed from test/libsolidity/syntaxTests/arrayLength/can_be_recursive_constant.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/cannot_be_function.sol (renamed from test/libsolidity/syntaxTests/arrayLength/cannot_be_function.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/cannot_be_function_call.sol (renamed from test/libsolidity/syntaxTests/arrayLength/cannot_be_function_call.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol (renamed from test/libsolidity/syntaxTests/arrayLength/complex_cyclic_constant.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/const_cannot_be_fractional.sol (renamed from test/libsolidity/syntaxTests/arrayLength/const_cannot_be_fractional.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/constant_var.sol (renamed from test/libsolidity/syntaxTests/arrayLength/constant_var.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/cyclic_constant.sol (renamed from test/libsolidity/syntaxTests/arrayLength/cyclic_constant.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/inline_array.sol (renamed from test/libsolidity/syntaxTests/arrayLength/inline_array.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/invalid_expression_1.sol (renamed from test/libsolidity/syntaxTests/arrayLength/invalid_expression_1.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/invalid_expression_2.sol (renamed from test/libsolidity/syntaxTests/arrayLength/invalid_expression_2.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/invalid_expression_3.sol (renamed from test/libsolidity/syntaxTests/arrayLength/invalid_expression_3.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/invalid_expression_4.sol (renamed from test/libsolidity/syntaxTests/arrayLength/invalid_expression_4.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/invalid_expression_5.sol (renamed from test/libsolidity/syntaxTests/arrayLength/invalid_expression_5.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/non_integer_constant_var.sol (renamed from test/libsolidity/syntaxTests/arrayLength/non_integer_constant_var.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/not_convertible_to_integer.sol (renamed from test/libsolidity/syntaxTests/arrayLength/not_convertible_to_integer.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/parentheses.sol (renamed from test/libsolidity/syntaxTests/arrayLength/parentheses.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/pure_functions.sol (renamed from test/libsolidity/syntaxTests/arrayLength/pure_functions.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/too_large.sol (renamed from test/libsolidity/syntaxTests/arrayLength/too_large.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/length/tuples.sol (renamed from test/libsolidity/syntaxTests/arrayLength/tuples.sol)0
-rw-r--r--test/libsolidity/syntaxTests/array/no_array_pop.sol8
-rw-r--r--test/libsolidity/syntaxTests/array/static_storage_array_pop.sol8
-rw-r--r--test/libsolidity/syntaxTests/array/string_pop.sol8
37 files changed, 457 insertions, 4 deletions
diff --git a/Changelog.md b/Changelog.md
index bba16d0b..13e3f676 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,7 @@
### 0.5.0 (unreleased)
+Language Features:
+ * General: Support ``pop()`` for storage arrays.
Breaking Changes:
* Disallow conversions between bytesX and uintY of different size.
diff --git a/docs/types.rst b/docs/types.rst
index 794a70de..b3631f74 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -682,7 +682,7 @@ possible:
It is planned to remove this restriction in the future but currently creates
some complications because of how arrays are passed in the ABI.
-.. index:: ! array;length, length, push, !array;push
+.. index:: ! array;length, length, push, pop, !array;push, !array;pop
Members
^^^^^^^
@@ -693,6 +693,8 @@ Members
``.length`` member. This does not happen automatically when attempting to access elements outside the current length. The size of memory arrays is fixed (but dynamic, i.e. it can depend on runtime parameters) once they are created.
**push**:
Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``push`` that can be used to append an element at the end of the array. The function returns the new length.
+**pop**:
+ Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``pop`` that can be used to remove an element from the end of the array.
.. warning::
It is not yet possible to use arrays of arrays in external functions.
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 8620f283..7f5ec46a 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -1697,6 +1697,7 @@ MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
{
members.push_back({"length", make_shared<IntegerType>(256)});
if (isDynamicallySized() && location() == DataLocation::Storage)
+ {
members.push_back({"push", make_shared<FunctionType>(
TypePointers{baseType()},
TypePointers{make_shared<IntegerType>(256)},
@@ -1704,6 +1705,14 @@ MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
strings{string()},
isByteArray() ? FunctionType::Kind::ByteArrayPush : FunctionType::Kind::ArrayPush
)});
+ members.push_back({"pop", make_shared<FunctionType>(
+ TypePointers{},
+ TypePointers{},
+ strings{string()},
+ strings{string()},
+ FunctionType::Kind::ArrayPop
+ )});
+ }
}
return members;
}
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 7c6f179b..b2f34dee 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -914,6 +914,7 @@ public:
AddMod, ///< ADDMOD
MulMod, ///< MULMOD
ArrayPush, ///< .push() to a dynamically sized array in storage
+ ArrayPop, ///< .pop() from a dynamically sized array in storage
ByteArrayPush, ///< .push() to a dynamically sized byte array in storage
ObjectCreation, ///< array creation using new
Assert, ///< assert()
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp
index 0fe66d2d..14c887c3 100644
--- a/libsolidity/codegen/ArrayUtils.cpp
+++ b/libsolidity/codegen/ArrayUtils.cpp
@@ -823,6 +823,85 @@ void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const
})", {"ref"});
}
+void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
+{
+ solAssert(_type.location() == DataLocation::Storage, "");
+ solAssert(_type.isDynamicallySized(), "");
+ if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32)
+ solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type.");
+
+ if (_type.isByteArray())
+ {
+ m_context.appendInlineAssembly(R"({
+ let slot_value := sload(ref)
+ switch and(slot_value, 1)
+ case 0 {
+ // short byte array
+ let length := and(div(slot_value, 2), 0x1f)
+ if iszero(length) { invalid() }
+
+ // Zero-out the suffix including the least significant byte.
+ let mask := sub(exp(0x100, sub(33, length)), 1)
+ length := sub(length, 1)
+ slot_value := or(and(not(mask), slot_value), mul(length, 2))
+ sstore(ref, slot_value)
+ }
+ case 1 {
+ // long byte array
+ mstore(0, ref)
+ let length := div(slot_value, 2)
+ let slot := keccak256(0, 0x20)
+ switch length
+ case 32
+ {
+ let data := sload(slot)
+ sstore(slot, 0)
+ data := and(data, not(0xff))
+ sstore(ref, or(data, 62))
+ }
+ default
+ {
+ let offset_inside_slot := and(sub(length, 1), 0x1f)
+ slot := add(slot, div(sub(length, 1), 32))
+ let data := sload(slot)
+
+ // Zero-out the suffix of the byte array by masking it.
+ // ((1<<(8 * (32 - offset))) - 1)
+ let mask := sub(exp(0x100, sub(32, offset_inside_slot)), 1)
+ data := and(not(mask), data)
+ sstore(slot, data)
+
+ // Reduce the length by 1
+ slot_value := sub(slot_value, 2)
+ sstore(ref, slot_value)
+ }
+ }
+ })", {"ref"});
+ m_context << Instruction::POP;
+ }
+ else
+ {
+ // stack: ArrayReference
+ retrieveLength(_type);
+ // stack: ArrayReference oldLength
+ m_context << Instruction::DUP1;
+ // stack: ArrayReference oldLength oldLength
+ m_context << Instruction::ISZERO;
+ m_context.appendConditionalInvalid();
+
+ // Stack: ArrayReference oldLength
+ m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB;
+ // Stack ArrayReference newLength
+ m_context << Instruction::DUP2 << Instruction::DUP2;
+ // Stack ArrayReference newLength ArrayReference newLength;
+ accessIndex(_type, false);
+ // Stack: ArrayReference newLength storage_slot byte_offset
+ StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), true);
+ // Stack: ArrayReference newLength
+ m_context << Instruction::SWAP1 << Instruction::SSTORE;
+ }
+}
+
void ArrayUtils::clearStorageLoop(TypePointer const& _type) const
{
m_context.callLowLevelFunction(
diff --git a/libsolidity/codegen/ArrayUtils.h b/libsolidity/codegen/ArrayUtils.h
index 99786397..daf50bf5 100644
--- a/libsolidity/codegen/ArrayUtils.h
+++ b/libsolidity/codegen/ArrayUtils.h
@@ -73,6 +73,11 @@ public:
/// Stack pre: reference (excludes byte offset)
/// Stack post: new_length
void incrementDynamicArraySize(ArrayType const& _type) const;
+ /// Decrements the size of a dynamic array by one if length is nonzero. Causes an invalid instruction otherwise.
+ /// Clears the removed data element. In case of a byte array, this might move the data.
+ /// Stack pre: reference
+ /// Stack post:
+ void popStorageArrayElement(ArrayType const& _type) const;
/// Appends a loop that clears a sequence of storage slots of the given type (excluding end).
/// Stack pre: end_ref start_ref
/// Stack post: end_ref
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 4bcc1fa9..93d440c8 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -866,6 +866,19 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true);
break;
}
+ case FunctionType::Kind::ArrayPop:
+ {
+ _functionCall.expression().accept(*this);
+ solAssert(function.parameterTypes().empty(), "");
+
+ ArrayType const& arrayType = dynamic_cast<ArrayType const&>(
+ *dynamic_cast<MemberAccess const&>(_functionCall.expression()).expression().annotation().type
+ );
+ solAssert(arrayType.dataStoredIn(DataLocation::Storage), "");
+
+ ArrayUtils(m_context).popStorageArrayElement(arrayType);
+ break;
+ }
case FunctionType::Kind::ObjectCreation:
{
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_functionCall.annotation().type);
@@ -1345,11 +1358,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
break;
}
}
- else if (member == "push")
+ else if (member == "push" || member == "pop")
{
solAssert(
- type.isDynamicallySized() && type.location() == DataLocation::Storage,
- "Tried to use .push() on a non-dynamically sized array"
+ type.isDynamicallySized() &&
+ type.location() == DataLocation::Storage &&
+ type.category() == Type::Category::Array,
+ "Tried to use ." + member + "() on a non-dynamically sized array"
);
}
else
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 40962294..f1fac396 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -5111,6 +5111,292 @@ BOOST_AUTO_TEST_CASE(byte_array_push_transition)
ABI_CHECK(callContractFunction("test()"), encodeArgs(0));
}
+BOOST_AUTO_TEST_CASE(array_pop)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint[] data;
+ function test() public returns (uint x, uint l) {
+ data.push(7);
+ x = data.push(3);
+ data.pop();
+ x = data.length;
+ data.pop();
+ l = data.length;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 0));
+}
+
+BOOST_AUTO_TEST_CASE(array_pop_uint16_transition)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint16[] data;
+ function test() public returns (uint16 x, uint16 y, uint16 z) {
+ for (uint i = 1; i <= 48; i++)
+ data.push(uint16(i));
+ for (uint j = 1; j <= 10; j++)
+ data.pop();
+ x = data[data.length - 1];
+ for (uint k = 1; k <= 10; k++)
+ data.pop();
+ y = data[data.length - 1];
+ for (uint l = 1; l <= 10; l++)
+ data.pop();
+ z = data[data.length - 1];
+ for (uint m = 1; m <= 18; m++)
+ data.pop();
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18));
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(array_pop_uint24_transition)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint256 a;
+ uint256 b;
+ uint256 c;
+ uint24[] data;
+ function test() public returns (uint24 x, uint24 y) {
+ for (uint i = 1; i <= 30; i++)
+ data.push(uint24(i));
+ for (uint j = 1; j <= 10; j++)
+ data.pop();
+ x = data[data.length - 1];
+ for (uint k = 1; k <= 10; k++)
+ data.pop();
+ y = data[data.length - 1];
+ for (uint l = 1; l <= 10; l++)
+ data.pop();
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10));
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(array_pop_array_transition)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint256 a;
+ uint256 b;
+ uint256 c;
+ uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+ uint16[][] data;
+ function test() public returns (uint x, uint y, uint z) {
+ for (uint i = 1; i <= 48; i++)
+ data.push(inner);
+ for (uint j = 1; j <= 10; j++)
+ data.pop();
+ x = data[data.length - 1][0];
+ for (uint k = 1; k <= 10; k++)
+ data.pop();
+ y = data[data.length - 1][1];
+ for (uint l = 1; l <= 10; l++)
+ data.pop();
+ z = data[data.length - 1][2];
+ for (uint m = 1; m <= 18; m++)
+ data.pop();
+ delete inner;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 2, 3));
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(array_pop_empty_exception)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint[] data;
+ function test() public returns (bool) {
+ data.pop();
+ return true;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(array_pop_storage_empty)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint[] data;
+ function test() public {
+ data.push(7);
+ data.pop();
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop)
+{
+ char const* sourceCode = R"(
+ contract c {
+ bytes data;
+ function test() public returns (uint x, uint y, uint l) {
+ data.push(7);
+ x = data.push(3);
+ data.pop();
+ data.pop();
+ y = data.push(2);
+ l = data.length;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 1, 1));
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop_empty_exception)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint256 a;
+ uint256 b;
+ uint256 c;
+ bytes data;
+ function test() public returns (bool) {
+ data.pop();
+ return true;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs());
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty)
+{
+ char const* sourceCode = R"(
+ contract c {
+ bytes data;
+ function test() public {
+ data.push(7);
+ data.push(5);
+ data.push(3);
+ data.pop();
+ data.pop();
+ data.pop();
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint256 a;
+ uint256 b;
+ uint256 c;
+ bytes data;
+ function test() public returns (bool) {
+ for (uint8 i = 0; i <= 40; i++)
+ data.push(byte(i+1));
+ for (int8 j = 40; j >= 0; j--) {
+ require(data[uint8(j)] == byte(j+1));
+ require(data.length == uint8(j+1));
+ data.pop();
+ }
+ return true;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(true));
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref)
+{
+ char const* sourceCode = R"(
+ contract c {
+ uint256 a;
+ uint256 b;
+ bytes data;
+ function test() public {
+ for (uint8 i = 0; i <= 40; i++)
+ data.push(3);
+ for (uint8 j = 0; j <= 40; j++) {
+ assembly {
+ mstore(0, "garbage")
+ }
+ data.pop();
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop_masking_long)
+{
+ char const* sourceCode = R"(
+ contract c {
+ bytes data;
+ function test() public returns (bytes) {
+ for (uint i = 0; i < 34; i++)
+ data.push(3);
+ data.pop();
+ return data;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(
+ u256(0x20),
+ u256(33),
+ asString(fromHex("0303030303030303030303030303030303030303030303030303030303030303")),
+ asString(fromHex("03"))
+ ));
+}
+
+BOOST_AUTO_TEST_CASE(byte_array_pop_copy_long)
+{
+ char const* sourceCode = R"(
+ contract c {
+ bytes data;
+ function test() public returns (bytes) {
+ for (uint i = 0; i < 33; i++)
+ data.push(3);
+ for (uint j = 0; j < 4; j++)
+ data.pop();
+ return data;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(
+ u256(0x20),
+ u256(29),
+ asString(fromHex("0303030303030303030303030303030303030303030303030303030303"))
+ ));
+}
+
BOOST_AUTO_TEST_CASE(external_array_args)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/syntaxTests/array/array_pop.sol b/test/libsolidity/syntaxTests/array/array_pop.sol
new file mode 100644
index 00000000..3804f911
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/array_pop.sol
@@ -0,0 +1,7 @@
+contract C {
+ uint[] data;
+ function test() public {
+ data.pop();
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/array/array_pop_arg.sol b/test/libsolidity/syntaxTests/array/array_pop_arg.sol
new file mode 100644
index 00000000..bb7803e2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/array_pop_arg.sol
@@ -0,0 +1,8 @@
+contract C {
+ uint[] data;
+ function test() public {
+ data.pop(5);
+ }
+}
+// ----
+// TypeError: (65-76): Wrong argument count for function call: 1 arguments given but expected 0.
diff --git a/test/libsolidity/syntaxTests/array/bytes_pop.sol b/test/libsolidity/syntaxTests/array/bytes_pop.sol
new file mode 100644
index 00000000..cd5aa0eb
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/bytes_pop.sol
@@ -0,0 +1,7 @@
+contract C {
+ bytes data;
+ function test() public {
+ data.pop();
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/array/dynamic_memory_array_pop.sol b/test/libsolidity/syntaxTests/array/dynamic_memory_array_pop.sol
new file mode 100644
index 00000000..5a79afc9
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/dynamic_memory_array_pop.sol
@@ -0,0 +1,8 @@
+contract C {
+ function test() public {
+ uint[] memory data;
+ data.pop();
+ }
+}
+// ----
+// TypeError: (74-82): Member "pop" is not available in uint256[] memory outside of storage.
diff --git a/test/libsolidity/syntaxTests/arrayLength/array_length_cannot_be_constant_function_parameter.sol b/test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol
index 11d40f26..11d40f26 100644
--- a/test/libsolidity/syntaxTests/arrayLength/array_length_cannot_be_constant_function_parameter.sol
+++ b/test/libsolidity/syntaxTests/array/length/array_length_cannot_be_constant_function_parameter.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/can_be_constant_in_function.sol b/test/libsolidity/syntaxTests/array/length/can_be_constant_in_function.sol
index 92536dd5..92536dd5 100644
--- a/test/libsolidity/syntaxTests/arrayLength/can_be_constant_in_function.sol
+++ b/test/libsolidity/syntaxTests/array/length/can_be_constant_in_function.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/can_be_constant_in_struct.sol b/test/libsolidity/syntaxTests/array/length/can_be_constant_in_struct.sol
index 89e174f2..89e174f2 100644
--- a/test/libsolidity/syntaxTests/arrayLength/can_be_constant_in_struct.sol
+++ b/test/libsolidity/syntaxTests/array/length/can_be_constant_in_struct.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/can_be_recursive_constant.sol b/test/libsolidity/syntaxTests/array/length/can_be_recursive_constant.sol
index 6810a9d6..6810a9d6 100644
--- a/test/libsolidity/syntaxTests/arrayLength/can_be_recursive_constant.sol
+++ b/test/libsolidity/syntaxTests/array/length/can_be_recursive_constant.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/cannot_be_function.sol b/test/libsolidity/syntaxTests/array/length/cannot_be_function.sol
index ac3abc4c..ac3abc4c 100644
--- a/test/libsolidity/syntaxTests/arrayLength/cannot_be_function.sol
+++ b/test/libsolidity/syntaxTests/array/length/cannot_be_function.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/cannot_be_function_call.sol b/test/libsolidity/syntaxTests/array/length/cannot_be_function_call.sol
index a6863955..a6863955 100644
--- a/test/libsolidity/syntaxTests/arrayLength/cannot_be_function_call.sol
+++ b/test/libsolidity/syntaxTests/array/length/cannot_be_function_call.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/complex_cyclic_constant.sol b/test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol
index 254f9f02..254f9f02 100644
--- a/test/libsolidity/syntaxTests/arrayLength/complex_cyclic_constant.sol
+++ b/test/libsolidity/syntaxTests/array/length/complex_cyclic_constant.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/const_cannot_be_fractional.sol b/test/libsolidity/syntaxTests/array/length/const_cannot_be_fractional.sol
index 397bbbcd..397bbbcd 100644
--- a/test/libsolidity/syntaxTests/arrayLength/const_cannot_be_fractional.sol
+++ b/test/libsolidity/syntaxTests/array/length/const_cannot_be_fractional.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/constant_var.sol b/test/libsolidity/syntaxTests/array/length/constant_var.sol
index 41750250..41750250 100644
--- a/test/libsolidity/syntaxTests/arrayLength/constant_var.sol
+++ b/test/libsolidity/syntaxTests/array/length/constant_var.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/cyclic_constant.sol b/test/libsolidity/syntaxTests/array/length/cyclic_constant.sol
index 91ba9045..91ba9045 100644
--- a/test/libsolidity/syntaxTests/arrayLength/cyclic_constant.sol
+++ b/test/libsolidity/syntaxTests/array/length/cyclic_constant.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/inline_array.sol b/test/libsolidity/syntaxTests/array/length/inline_array.sol
index a30745d3..a30745d3 100644
--- a/test/libsolidity/syntaxTests/arrayLength/inline_array.sol
+++ b/test/libsolidity/syntaxTests/array/length/inline_array.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_1.sol b/test/libsolidity/syntaxTests/array/length/invalid_expression_1.sol
index c92861eb..c92861eb 100644
--- a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_1.sol
+++ b/test/libsolidity/syntaxTests/array/length/invalid_expression_1.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_2.sol b/test/libsolidity/syntaxTests/array/length/invalid_expression_2.sol
index 92e3c3cf..92e3c3cf 100644
--- a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_2.sol
+++ b/test/libsolidity/syntaxTests/array/length/invalid_expression_2.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_3.sol b/test/libsolidity/syntaxTests/array/length/invalid_expression_3.sol
index 26add45c..26add45c 100644
--- a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_3.sol
+++ b/test/libsolidity/syntaxTests/array/length/invalid_expression_3.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_4.sol b/test/libsolidity/syntaxTests/array/length/invalid_expression_4.sol
index a0d58f4a..a0d58f4a 100644
--- a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_4.sol
+++ b/test/libsolidity/syntaxTests/array/length/invalid_expression_4.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_5.sol b/test/libsolidity/syntaxTests/array/length/invalid_expression_5.sol
index 38a80867..38a80867 100644
--- a/test/libsolidity/syntaxTests/arrayLength/invalid_expression_5.sol
+++ b/test/libsolidity/syntaxTests/array/length/invalid_expression_5.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/non_integer_constant_var.sol b/test/libsolidity/syntaxTests/array/length/non_integer_constant_var.sol
index 7a853a34..7a853a34 100644
--- a/test/libsolidity/syntaxTests/arrayLength/non_integer_constant_var.sol
+++ b/test/libsolidity/syntaxTests/array/length/non_integer_constant_var.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/not_convertible_to_integer.sol b/test/libsolidity/syntaxTests/array/length/not_convertible_to_integer.sol
index b44ccfe9..b44ccfe9 100644
--- a/test/libsolidity/syntaxTests/arrayLength/not_convertible_to_integer.sol
+++ b/test/libsolidity/syntaxTests/array/length/not_convertible_to_integer.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/parentheses.sol b/test/libsolidity/syntaxTests/array/length/parentheses.sol
index 40f55ad6..40f55ad6 100644
--- a/test/libsolidity/syntaxTests/arrayLength/parentheses.sol
+++ b/test/libsolidity/syntaxTests/array/length/parentheses.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/pure_functions.sol b/test/libsolidity/syntaxTests/array/length/pure_functions.sol
index b620db76..b620db76 100644
--- a/test/libsolidity/syntaxTests/arrayLength/pure_functions.sol
+++ b/test/libsolidity/syntaxTests/array/length/pure_functions.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/too_large.sol b/test/libsolidity/syntaxTests/array/length/too_large.sol
index c90a7494..c90a7494 100644
--- a/test/libsolidity/syntaxTests/arrayLength/too_large.sol
+++ b/test/libsolidity/syntaxTests/array/length/too_large.sol
diff --git a/test/libsolidity/syntaxTests/arrayLength/tuples.sol b/test/libsolidity/syntaxTests/array/length/tuples.sol
index bc10b3b5..bc10b3b5 100644
--- a/test/libsolidity/syntaxTests/arrayLength/tuples.sol
+++ b/test/libsolidity/syntaxTests/array/length/tuples.sol
diff --git a/test/libsolidity/syntaxTests/array/no_array_pop.sol b/test/libsolidity/syntaxTests/array/no_array_pop.sol
new file mode 100644
index 00000000..44e54ad2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/no_array_pop.sol
@@ -0,0 +1,8 @@
+contract C {
+ uint data;
+ function test() public {
+ data.pop();
+ }
+}
+// ----
+// TypeError: (63-71): Member "pop" not found or not visible after argument-dependent lookup in uint256
diff --git a/test/libsolidity/syntaxTests/array/static_storage_array_pop.sol b/test/libsolidity/syntaxTests/array/static_storage_array_pop.sol
new file mode 100644
index 00000000..0af171ad
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/static_storage_array_pop.sol
@@ -0,0 +1,8 @@
+contract C {
+ uint[3] data;
+ function test() public {
+ data.pop();
+ }
+}
+// ----
+// TypeError: (66-74): Member "pop" not found or not visible after argument-dependent lookup in uint256[3] storage ref
diff --git a/test/libsolidity/syntaxTests/array/string_pop.sol b/test/libsolidity/syntaxTests/array/string_pop.sol
new file mode 100644
index 00000000..2a46d0c3
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/string_pop.sol
@@ -0,0 +1,8 @@
+contract C {
+ string data;
+ function test() public {
+ data.pop();
+ }
+}
+// ----
+// TypeError: (65-73): Member "pop" not found or not visible after argument-dependent lookup in string storage ref