diff options
15 files changed, 255 insertions, 103 deletions
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 5f6d7d50..82c9f67a 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -410,15 +410,19 @@ A function description is a JSON object with the fields: * ``components``: used for tuple types (more below). - ``outputs``: an array of objects similar to ``inputs``, can be omitted if function doesn't return anything; -- ``payable``: ``true`` if function accepts ether, defaults to ``false``; -- ``stateMutability``: a string with one of the following values: ``pure`` (:ref:`specified to not read blockchain state <pure-functions>`), ``view`` (:ref:`specified to not modify the blockchain state <view-functions>`), ``nonpayable`` and ``payable`` (same as ``payable`` above). -- ``constant``: ``true`` if function is either ``pure`` or ``view`` +- ``stateMutability``: a string with one of the following values: ``pure`` (:ref:`specified to not read blockchain state <pure-functions>`), ``view`` (:ref:`specified to not modify the blockchain state <view-functions>`), ``nonpayable`` (function does not accept ether) and ``payable`` (function accepts ether); +- ``payable``: ``true`` if function accepts ether, ``false`` otherwise; +- ``constant``: ``true`` if function is either ``pure`` or ``view``, ``false`` otherwise. -``type`` can be omitted, defaulting to ``"function"``. +``type`` can be omitted, defaulting to ``"function"``, likewise ``payable`` and ``constant`` can be omitted, both defaulting to ``false``. Constructor and fallback function never have ``name`` or ``outputs``. Fallback function doesn't have ``inputs`` either. -Sending non-zero ether to non-payable function will throw. Don't do it. +.. warning:: + The fields ``constant`` and ``payable`` are deprecated and will be removed in the future. Instead, the ``stateMutability`` field can be used to determine the same properties. + +.. note:: + Sending non-zero ether to non-payable function will revert the transaction. An event description is a JSON object with fairly similar fields: diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp index e2a51267..2623a2ba 100644 --- a/libsolidity/formal/SMTChecker.cpp +++ b/libsolidity/formal/SMTChecker.cpp @@ -429,7 +429,14 @@ void SMTChecker::arithmeticOperation(BinaryOperation const& _op) case Token::Div: { solAssert(_op.annotation().commonType, ""); - solAssert(_op.annotation().commonType->category() == Type::Category::Integer, ""); + if (_op.annotation().commonType->category() != Type::Category::Integer) + { + m_errorReporter.warning( + _op.location(), + "Assertion checker does not yet implement this operator on non-integer types." + ); + break; + } auto const& intType = dynamic_cast<IntegerType const&>(*_op.annotation().commonType); smt::Expression left(expr(_op.leftExpression())); smt::Expression right(expr(_op.rightExpression())); @@ -752,6 +759,7 @@ void SMTChecker::mergeVariables(vector<VariableDeclaration const*> const& _varia set<VariableDeclaration const*> uniqueVars(_variables.begin(), _variables.end()); for (auto const* decl: uniqueVars) { + solAssert(_countersEndTrue.count(decl) && _countersEndFalse.count(decl), ""); int trueCounter = _countersEndTrue.at(decl).index(); int falseCounter = _countersEndFalse.at(decl).index(); solAssert(trueCounter != falseCounter, ""); diff --git a/test/compilationTests/stringutils/strings.sol b/test/compilationTests/stringutils/strings.sol index 390fb5d9..6865664b 100644 --- a/test/compilationTests/stringutils/strings.sol +++ b/test/compilationTests/stringutils/strings.sol @@ -33,13 +33,16 @@ * `s.splitNew('.')` leaves s unmodified, and returns two values * corresponding to the left and right parts of the string. */ + +pragma solidity ^0.4.14; + library strings { struct slice { uint _len; uint _ptr; } - function memcpy(uint dest, uint src, uint len) private { + function memcpy(uint dest, uint src, uint len) private pure { // Copy word-length chunks while possible for(; len >= 32; len -= 32) { assembly { @@ -63,7 +66,7 @@ library strings { * @param self The string to make a slice from. * @return A newly allocated slice containing the entire string. */ - function toSlice(string memory self) internal returns (slice memory) { + function toSlice(string memory self) internal pure returns (slice memory) { uint ptr; assembly { ptr := add(self, 0x20) @@ -76,7 +79,7 @@ library strings { * @param self The value to find the length of. * @return The length of the string, from 0 to 32. */ - function len(bytes32 self) internal returns (uint) { + function len(bytes32 self) internal pure returns (uint) { uint ret; if (self == 0) return 0; @@ -104,12 +107,12 @@ library strings { /* * @dev Returns a slice containing the entire bytes32, interpreted as a - * null-termintaed utf-8 string. + * null-terminated utf-8 string. * @param self The bytes32 value to convert to a slice. * @return A new slice containing the value of the input argument up to the * first null. */ - function toSliceB32(bytes32 self) internal returns (slice memory ret) { + function toSliceB32(bytes32 self) internal pure returns (slice memory ret) { // Allocate space for `self` in memory, copy it there, and point ret at it assembly { let ptr := mload(0x40) @@ -125,7 +128,7 @@ library strings { * @param self The slice to copy. * @return A new slice containing the same data as `self`. */ - function copy(slice memory self) internal returns (slice memory) { + function copy(slice memory self) internal pure returns (slice memory) { return slice(self._len, self._ptr); } @@ -134,7 +137,7 @@ library strings { * @param self The slice to copy. * @return A newly allocated string containing the slice's text. */ - function toString(slice memory self) internal returns (string memory) { + function toString(slice memory self) internal pure returns (string memory) { string memory ret = new string(self._len); uint retptr; assembly { retptr := add(ret, 32) } @@ -151,12 +154,11 @@ library strings { * @param self The slice to operate on. * @return The length of the slice in runes. */ - function len(slice memory self) internal returns (uint) { + function len(slice memory self) internal pure returns (uint l) { // Starting at ptr-31 means the LSB will be the byte we care about uint ptr = self._ptr - 31; uint end = ptr + self._len; - uint len; - for (len = 0; ptr < end; len++) { + for (l = 0; ptr < end; l++) { uint8 b; assembly { b := and(mload(ptr), 0xFF) } if (b < 0x80) { @@ -173,7 +175,6 @@ library strings { ptr += 6; } } - return len; } /* @@ -181,7 +182,7 @@ library strings { * @param self The slice to operate on. * @return True if the slice is empty, False otherwise. */ - function empty(slice memory self) internal returns (bool) { + function empty(slice memory self) internal pure returns (bool) { return self._len == 0; } @@ -194,7 +195,7 @@ library strings { * @param other The second slice to compare. * @return The result of the comparison. */ - function compare(slice memory self, slice memory other) internal returns (int) { + function compare(slice memory self, slice memory other) internal pure returns (int) { uint shortest = self._len; if (other._len < self._len) shortest = other._len; @@ -210,8 +211,11 @@ library strings { } if (a != b) { // Mask out irrelevant bytes and check again - uint mask = ~(2 ** (8 * (32 - shortest + idx)) - 1); - uint diff = (a & mask) - (b & mask); + uint256 mask = uint256(-1); // 0xffff... + if(shortest < 32) { + mask = ~(2 ** (8 * (32 - shortest + idx)) - 1); + } + uint256 diff = (a & mask) - (b & mask); if (diff != 0) return int(diff); } @@ -227,7 +231,7 @@ library strings { * @param self The second slice to compare. * @return True if the slices are equal, false otherwise. */ - function equals(slice memory self, slice memory other) internal returns (bool) { + function equals(slice memory self, slice memory other) internal pure returns (bool) { return compare(self, other) == 0; } @@ -238,7 +242,7 @@ library strings { * @param rune The slice that will contain the first rune. * @return `rune`. */ - function nextRune(slice memory self, slice memory rune) internal returns (slice memory) { + function nextRune(slice memory self, slice memory rune) internal pure returns (slice memory) { rune._ptr = self._ptr; if (self._len == 0) { @@ -246,31 +250,31 @@ library strings { return rune; } - uint len; + uint l; uint b; // Load the first byte of the rune into the LSBs of b assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) } if (b < 0x80) { - len = 1; + l = 1; } else if(b < 0xE0) { - len = 2; + l = 2; } else if(b < 0xF0) { - len = 3; + l = 3; } else { - len = 4; + l = 4; } // Check for truncated codepoints - if (len > self._len) { + if (l > self._len) { rune._len = self._len; self._ptr += self._len; self._len = 0; return rune; } - self._ptr += len; - self._len -= len; - rune._len = len; + self._ptr += l; + self._len -= l; + rune._len = l; return rune; } @@ -280,7 +284,7 @@ library strings { * @param self The slice to operate on. * @return A slice containing only the first rune from `self`. */ - function nextRune(slice memory self) internal returns (slice memory ret) { + function nextRune(slice memory self) internal pure returns (slice memory ret) { nextRune(self, ret); } @@ -289,40 +293,40 @@ library strings { * @param self The slice to operate on. * @return The number of the first codepoint in the slice. */ - function ord(slice memory self) internal returns (uint ret) { + function ord(slice memory self) internal pure returns (uint ret) { if (self._len == 0) { return 0; } uint word; - uint len; - uint div = 2 ** 248; + uint length; + uint divisor = 2 ** 248; // Load the rune into the MSBs of b assembly { word:= mload(mload(add(self, 32))) } - uint b = word / div; + uint b = word / divisor; if (b < 0x80) { ret = b; - len = 1; + length = 1; } else if(b < 0xE0) { ret = b & 0x1F; - len = 2; + length = 2; } else if(b < 0xF0) { ret = b & 0x0F; - len = 3; + length = 3; } else { ret = b & 0x07; - len = 4; + length = 4; } // Check for truncated codepoints - if (len > self._len) { + if (length > self._len) { return 0; } - for (uint i = 1; i < len; i++) { - div = div / 256; - b = (word / div) & 0xFF; + for (uint i = 1; i < length; i++) { + divisor = divisor / 256; + b = (word / divisor) & 0xFF; if (b & 0xC0 != 0x80) { // Invalid UTF-8 sequence return 0; @@ -338,7 +342,7 @@ library strings { * @param self The slice to hash. * @return The hash of the slice. */ - function keccak(slice memory self) internal returns (bytes32 ret) { + function keccak(slice memory self) internal pure returns (bytes32 ret) { assembly { ret := keccak256(mload(add(self, 32)), mload(self)) } @@ -350,7 +354,7 @@ library strings { * @param needle The slice to search for. * @return True if the slice starts with the provided text, false otherwise. */ - function startsWith(slice memory self, slice memory needle) internal returns (bool) { + function startsWith(slice memory self, slice memory needle) internal pure returns (bool) { if (self._len < needle._len) { return false; } @@ -361,10 +365,10 @@ library strings { bool equal; assembly { - let len := mload(needle) + let length := mload(needle) let selfptr := mload(add(self, 0x20)) let needleptr := mload(add(needle, 0x20)) - equal := eq(keccak256(selfptr, len), keccak256(needleptr, len)) + equal := eq(keccak256(selfptr, length), keccak256(needleptr, length)) } return equal; } @@ -376,7 +380,7 @@ library strings { * @param needle The slice to search for. * @return `self` */ - function beyond(slice memory self, slice memory needle) internal returns (slice memory) { + function beyond(slice memory self, slice memory needle) internal pure returns (slice memory) { if (self._len < needle._len) { return self; } @@ -384,10 +388,10 @@ library strings { bool equal = true; if (self._ptr != needle._ptr) { assembly { - let len := mload(needle) + let length := mload(needle) let selfptr := mload(add(self, 0x20)) let needleptr := mload(add(needle, 0x20)) - equal := eq(keccak256(selfptr, len), keccak256(needleptr, len)) + equal := eq(keccak256(selfptr, length), keccak256(needleptr, length)) } } @@ -405,7 +409,7 @@ library strings { * @param needle The slice to search for. * @return True if the slice starts with the provided text, false otherwise. */ - function endsWith(slice memory self, slice memory needle) internal returns (bool) { + function endsWith(slice memory self, slice memory needle) internal pure returns (bool) { if (self._len < needle._len) { return false; } @@ -418,9 +422,9 @@ library strings { bool equal; assembly { - let len := mload(needle) + let length := mload(needle) let needleptr := mload(add(needle, 0x20)) - equal := eq(keccak256(selfptr, len), keccak256(needleptr, len)) + equal := eq(keccak256(selfptr, length), keccak256(needleptr, length)) } return equal; @@ -433,7 +437,7 @@ library strings { * @param needle The slice to search for. * @return `self` */ - function until(slice memory self, slice memory needle) internal returns (slice memory) { + function until(slice memory self, slice memory needle) internal pure returns (slice memory) { if (self._len < needle._len) { return self; } @@ -442,9 +446,9 @@ library strings { bool equal = true; if (selfptr != needle._ptr) { assembly { - let len := mload(needle) + let length := mload(needle) let needleptr := mload(add(needle, 0x20)) - equal := eq(keccak256(selfptr, len), keccak256(needleptr, len)) + equal := eq(keccak256(selfptr, length), keccak256(needleptr, length)) } } @@ -457,31 +461,33 @@ library strings { // Returns the memory address of the first byte of the first occurrence of // `needle` in `self`, or the first byte after `self` if not found. - function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) { - uint ptr; + function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) { + uint ptr = selfptr; uint idx; if (needlelen <= selflen) { if (needlelen <= 32) { - // Optimized assembly for 68 gas per byte on short strings - assembly { - let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1)) - let needledata := and(mload(needleptr), mask) - let end := add(selfptr, sub(selflen, needlelen)) - ptr := selfptr - loop: - jumpi(exit, eq(and(mload(ptr), mask), needledata)) - ptr := add(ptr, 1) - jumpi(loop, lt(sub(ptr, 1), end)) - ptr := add(selfptr, selflen) - exit: + bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1)); + + bytes32 needledata; + assembly { needledata := and(mload(needleptr), mask) } + + uint end = selfptr + selflen - needlelen; + bytes32 ptrdata; + assembly { ptrdata := and(mload(ptr), mask) } + + while (ptrdata != needledata) { + if (ptr >= end) + return selfptr + selflen; + ptr++; + assembly { ptrdata := and(mload(ptr), mask) } } return ptr; } else { // For long needles, use hashing bytes32 hash; assembly { hash := keccak256(needleptr, needlelen) } - ptr = selfptr; + for (idx = 0; idx <= selflen - needlelen; idx++) { bytes32 testHash; assembly { testHash := keccak256(ptr, needlelen) } @@ -496,27 +502,27 @@ library strings { // Returns the memory address of the first byte after the last occurrence of // `needle` in `self`, or the address of `self` if not found. - function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) { + function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) { uint ptr; if (needlelen <= selflen) { if (needlelen <= 32) { - // Optimized assembly for 69 gas per byte on short strings - assembly { - let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1)) - let needledata := and(mload(needleptr), mask) - ptr := add(selfptr, sub(selflen, needlelen)) - loop: - jumpi(ret, eq(and(mload(ptr), mask), needledata)) - ptr := sub(ptr, 1) - jumpi(loop, gt(add(ptr, 1), selfptr)) - ptr := selfptr - jump(exit) - ret: - ptr := add(ptr, needlelen) - exit: + bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1)); + + bytes32 needledata; + assembly { needledata := and(mload(needleptr), mask) } + + ptr = selfptr + selflen - needlelen; + bytes32 ptrdata; + assembly { ptrdata := and(mload(ptr), mask) } + + while (ptrdata != needledata) { + if (ptr <= selfptr) + return selfptr; + ptr--; + assembly { ptrdata := and(mload(ptr), mask) } } - return ptr; + return ptr + needlelen; } else { // For long needles, use hashing bytes32 hash; @@ -542,7 +548,7 @@ library strings { * @param needle The text to search for. * @return `self`. */ - function find(slice memory self, slice memory needle) internal returns (slice memory) { + function find(slice memory self, slice memory needle) internal pure returns (slice memory) { uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr); self._len -= ptr - self._ptr; self._ptr = ptr; @@ -557,7 +563,7 @@ library strings { * @param needle The text to search for. * @return `self`. */ - function rfind(slice memory self, slice memory needle) internal returns (slice memory) { + function rfind(slice memory self, slice memory needle) internal pure returns (slice memory) { uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr); self._len = ptr - self._ptr; return self; @@ -573,7 +579,7 @@ library strings { * @param token An output parameter to which the first token is written. * @return `token`. */ - function split(slice memory self, slice memory needle, slice memory token) internal returns (slice memory) { + function split(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) { uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr); token._ptr = self._ptr; token._len = ptr - self._ptr; @@ -596,7 +602,7 @@ library strings { * @param needle The text to search for in `self`. * @return The part of `self` up to the first occurrence of `delim`. */ - function split(slice memory self, slice memory needle) internal returns (slice memory token) { + function split(slice memory self, slice memory needle) internal pure returns (slice memory token) { split(self, needle, token); } @@ -610,7 +616,7 @@ library strings { * @param token An output parameter to which the first token is written. * @return `token`. */ - function rsplit(slice memory self, slice memory needle, slice memory token) internal returns (slice memory) { + function rsplit(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) { uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr); token._ptr = ptr; token._len = self._len - (ptr - self._ptr); @@ -632,7 +638,7 @@ library strings { * @param needle The text to search for in `self`. * @return The part of `self` after the last occurrence of `delim`. */ - function rsplit(slice memory self, slice memory needle) internal returns (slice memory token) { + function rsplit(slice memory self, slice memory needle) internal pure returns (slice memory token) { rsplit(self, needle, token); } @@ -642,10 +648,10 @@ library strings { * @param needle The text to search for in `self`. * @return The number of occurrences of `needle` found in `self`. */ - function count(slice memory self, slice memory needle) internal returns (uint count) { + function count(slice memory self, slice memory needle) internal pure returns (uint cnt) { uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len; while (ptr <= self._ptr + self._len) { - count++; + cnt++; ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len; } } @@ -656,7 +662,7 @@ library strings { * @param needle The text to search for in `self`. * @return True if `needle` is found in `self`, false otherwise. */ - function contains(slice memory self, slice memory needle) internal returns (bool) { + function contains(slice memory self, slice memory needle) internal pure returns (bool) { return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr; } @@ -667,7 +673,7 @@ library strings { * @param other The second slice to concatenate. * @return The concatenation of the two strings. */ - function concat(slice memory self, slice memory other) internal returns (string memory) { + function concat(slice memory self, slice memory other) internal pure returns (string memory) { string memory ret = new string(self._len + other._len); uint retptr; assembly { retptr := add(ret, 32) } @@ -684,15 +690,15 @@ library strings { * @return A newly allocated string containing all the slices in `parts`, * joined with `self`. */ - function join(slice memory self, slice[] memory parts) internal returns (string memory) { + function join(slice memory self, slice[] memory parts) internal pure returns (string memory) { if (parts.length == 0) return ""; - uint len = self._len * (parts.length - 1); + uint length = self._len * (parts.length - 1); for(uint i = 0; i < parts.length; i++) - len += parts[i]._len; + length += parts[i]._len; - string memory ret = new string(len); + string memory ret = new string(length); uint retptr; assembly { retptr := add(ret, 32) } diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_contract.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_contract.sol new file mode 100644 index 00000000..a87a3e66 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_contract.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure { + assembly { + let x := C + } + } +} +// ---- +// TypeError: (72-73): Expected a library. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol new file mode 100644 index 00000000..ecda3e99 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + assembly { + let x := f + } + } +} diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_library.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_library.sol new file mode 100644 index 00000000..3c551c18 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_library.sol @@ -0,0 +1,10 @@ +library L { +} + +contract C { + function f() public pure { + assembly { + let x := L + } + } +} diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_super.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_super.sol new file mode 100644 index 00000000..bd5562d5 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_super.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure { + assembly { + let x := super + } + } +} +// ---- +// DeclarationError: (72-77): Identifier not found. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_special.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_special.sol new file mode 100644 index 00000000..db28e507 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_special.sol @@ -0,0 +1,13 @@ +contract C { + function f() public { + assembly { + super := 1 + f := 1 + C := 1 + } + } +} +// ---- +// TypeError: (58-63): Only local variables can be assigned to in inline assembly. +// TypeError: (75-76): Only local variables can be assigned to in inline assembly. +// TypeError: (88-89): Only local variables can be assigned to in inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/function_call_invalid_argument_count.sol b/test/libsolidity/syntaxTests/inlineAssembly/function_call_invalid_argument_count.sol new file mode 100644 index 00000000..cbea8991 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/function_call_invalid_argument_count.sol @@ -0,0 +1,16 @@ +contract C { + function f() public pure { + assembly { + function f(a) {} + + f() + f(1) + f(1, 2) + } + } +} +// ---- +// TypeError: (87-88): Expected 1 arguments but got 0. +// Warning: (87-90): Top-level expressions are not supposed to return values (this expression returns -1 values). Use ``pop()`` or assign them. +// TypeError: (108-109): Expected 1 arguments but got 2. +// Warning: (108-115): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/function_call_not_found.sol b/test/libsolidity/syntaxTests/inlineAssembly/function_call_not_found.sol new file mode 100644 index 00000000..57534bd6 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/function_call_not_found.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure { + assembly { + k() + } + } +} +// ---- +// DeclarationError: (63-64): Function not found. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/function_call_to_label.sol b/test/libsolidity/syntaxTests/inlineAssembly/function_call_to_label.sol new file mode 100644 index 00000000..5de492e1 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/function_call_to_label.sol @@ -0,0 +1,13 @@ +contract C { + function f() public pure { + assembly { + l: + + l() + } + } +} +// ---- +// Warning: (63-64): The use of labels is deprecated. Please use "if", "switch", "for" or function calls instead. +// Warning: (63-64): Jump instructions and labels are low-level EVM features that can lead to incorrect stack access. Because of that they are discouraged. Please consider using "switch", "if" or "for" statements instead. +// TypeError: (73-74): Attempt to call label instead of function. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/function_call_to_variable.sol b/test/libsolidity/syntaxTests/inlineAssembly/function_call_to_variable.sol new file mode 100644 index 00000000..c0071855 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/function_call_to_variable.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + assembly { + let x := 1 + + x() + } + } +} +// ---- +// TypeError: (81-82): Attempt to call variable instead of function. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/function_without_call.sol b/test/libsolidity/syntaxTests/inlineAssembly/function_without_call.sol new file mode 100644 index 00000000..8557e2fa --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/function_without_call.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + assembly { + function k() {} + + k + } + } +} +// ---- +// TypeError: (86-87): Function k used without being called. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_assignment.sol b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_assignment.sol new file mode 100644 index 00000000..d5c8eaf5 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_assignment.sol @@ -0,0 +1,13 @@ +contract C { + uint[] x; + function() external { + uint[] storage y = x; + assembly { + y_slot := 1 + y_offset := 2 + } + } +} +// ---- +// TypeError: (115-121): Storage variables cannot be assigned to. +// TypeError: (139-147): Storage variables cannot be assigned to. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_memory.sol b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_memory.sol new file mode 100644 index 00000000..4025e11c --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/storage_reference_on_memory.sol @@ -0,0 +1,13 @@ +contract C { + uint[] x; + function() external { + uint[] memory y = x; + assembly { + pop(y_slot) + pop(y_offset) + } + } +} +// ---- +// TypeError: (118-124): The suffixes _offset and _slot can only be used on storage variables. +// TypeError: (142-150): The suffixes _offset and _slot can only be used on storage variables. |