mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use .slot
and .offest
to access storage items.
This commit is contained in:
parent
8eee3ed3a2
commit
fc2e9ec2ff
@ -33,6 +33,7 @@
|
|||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
#include <libsolutil/StringUtils.h>
|
#include <libsolutil/StringUtils.h>
|
||||||
|
#include <libsolutil/CommonData.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
@ -195,9 +196,10 @@ void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
|
|||||||
|
|
||||||
void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot");
|
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), ".slot");
|
||||||
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset");
|
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), ".offset");
|
||||||
|
|
||||||
|
// Could also use `pathFromCurrentScope`, split by '.'
|
||||||
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
|
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
|
||||||
if (isSlot || isOffset)
|
if (isSlot || isOffset)
|
||||||
{
|
{
|
||||||
@ -207,19 +209,22 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
|||||||
return;
|
return;
|
||||||
string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - (
|
string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - (
|
||||||
isSlot ?
|
isSlot ?
|
||||||
string("_slot").size() :
|
string(".slot").size() :
|
||||||
string("_offset").size()
|
string(".offset").size()
|
||||||
));
|
));
|
||||||
if (realName.empty())
|
if (realName.empty())
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
4794_error,
|
4794_error,
|
||||||
_identifier.location,
|
_identifier.location,
|
||||||
"In variable names _slot and _offset can only be used as a suffix."
|
"In variable names .slot and .offset can only be used as a suffix."
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
declarations = m_resolver.nameFromCurrentScope(realName);
|
declarations = m_resolver.nameFromCurrentScope(realName);
|
||||||
|
if (!declarations.empty())
|
||||||
|
// To support proper path resolution, we have to use pathFromCurrentScope.
|
||||||
|
solAssert(!util::contains(realName, '.'), "");
|
||||||
}
|
}
|
||||||
if (declarations.size() > 1)
|
if (declarations.size() > 1)
|
||||||
{
|
{
|
||||||
@ -231,7 +236,18 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (declarations.size() == 0)
|
else if (declarations.size() == 0)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
boost::algorithm::ends_with(_identifier.name.str(), "_slot") ||
|
||||||
|
boost::algorithm::ends_with(_identifier.name.str(), "_offset")
|
||||||
|
)
|
||||||
|
m_errorReporter.declarationError(
|
||||||
|
9467_error,
|
||||||
|
_identifier.location,
|
||||||
|
"Identifier not found. Use ``.slot`` and ``.offset`` to access storage variables."
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
|
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
|
||||||
if (var->isLocalVariable() && m_yulInsideFunction)
|
if (var->isLocalVariable() && m_yulInsideFunction)
|
||||||
{
|
{
|
||||||
@ -254,18 +270,9 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
|||||||
{
|
{
|
||||||
validateYulIdentifierName(identifier.name, identifier.location);
|
validateYulIdentifierName(identifier.name, identifier.location);
|
||||||
|
|
||||||
bool isSlot = boost::algorithm::ends_with(identifier.name.str(), "_slot");
|
|
||||||
bool isOffset = boost::algorithm::ends_with(identifier.name.str(), "_offset");
|
|
||||||
|
|
||||||
string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
|
if (
|
||||||
if (isSlot || isOffset)
|
auto declarations = m_resolver.nameFromCurrentScope(identifier.name.str());
|
||||||
m_errorReporter.declarationError(
|
|
||||||
9155_error,
|
|
||||||
identifier.location,
|
|
||||||
"In variable declarations _slot and _offset can not be used as a suffix."
|
|
||||||
);
|
|
||||||
else if (
|
|
||||||
auto declarations = m_resolver.nameFromCurrentScope(namePrefix);
|
|
||||||
!declarations.empty()
|
!declarations.empty()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -277,8 +284,6 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
|||||||
3859_error,
|
3859_error,
|
||||||
identifier.location,
|
identifier.location,
|
||||||
ssl,
|
ssl,
|
||||||
namePrefix.size() < identifier.name.str().size() ?
|
|
||||||
"The prefix of this declaration conflicts with a declaration outside the inline assembly block." :
|
|
||||||
"This declaration shadows a declaration outside the inline assembly block."
|
"This declaration shadows a declaration outside the inline assembly block."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -767,7 +767,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (requiresStorage)
|
else if (requiresStorage)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes .offset and .slot can only be used on non-constant storage variables.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||||
@ -795,7 +795,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
{
|
{
|
||||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes .offset and .slot can only be used on storage variables.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
@ -807,7 +807,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (identifierInfo.isOffset)
|
else if (identifierInfo.isOffset)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
m_errorReporter.typeError(9739_error, _identifier.location, "Only .slot can be assigned to.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -816,12 +816,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (!var->isConstant() && var->isStateVariable())
|
else if (!var->isConstant() && var->isStateVariable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the .slot or .offset suffix to access storage reference variables.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (var->type()->sizeOnStack() != 1)
|
else if (var->type()->sizeOnStack() != 1)
|
||||||
@ -835,7 +835,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
}
|
}
|
||||||
else if (requiresStorage)
|
else if (requiresStorage)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes .offset and .slot can only be used on storage variables.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
"src": "97:17:1",
|
"src": "97:17:1",
|
||||||
"value":
|
"value":
|
||||||
{
|
{
|
||||||
"name": "s_offset",
|
"name": "s.offset",
|
||||||
"nodeType": "YulIdentifier",
|
"nodeType": "YulIdentifier",
|
||||||
"src": "106:8:1"
|
"src": "106:8:1"
|
||||||
},
|
},
|
||||||
@ -139,7 +139,7 @@
|
|||||||
"arguments":
|
"arguments":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "s_slot",
|
"name": "s.slot",
|
||||||
"nodeType": "YulIdentifier",
|
"nodeType": "YulIdentifier",
|
||||||
"src": "128:6:1"
|
"src": "128:6:1"
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@ contract C {
|
|||||||
struct S { uint x; }
|
struct S { uint x; }
|
||||||
S s;
|
S s;
|
||||||
function e() pure public {
|
function e() pure public {
|
||||||
assembly { let x := s_offset let y := mul(s_slot, 2) }
|
assembly { let x := s.offset let y := mul(s.slot, 2) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@
|
|||||||
"valueSize": 1
|
"valueSize": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"operations": "{\n let x := s_offset\n let y := mul(s_slot, 2)\n}"
|
"operations": "{\n let x := s.offset\n let y := mul(s.slot, 2)\n}"
|
||||||
},
|
},
|
||||||
"children": [],
|
"children": [],
|
||||||
"id": 8,
|
"id": 8,
|
||||||
|
@ -2,38 +2,38 @@ contract c {
|
|||||||
bytes data;
|
bytes data;
|
||||||
function test_short() public returns (uint256 r) {
|
function test_short() public returns (uint256 r) {
|
||||||
assembly {
|
assembly {
|
||||||
sstore(data_slot, 0)
|
sstore(data.slot, 0)
|
||||||
}
|
}
|
||||||
for (uint8 i = 0; i < 15; i++) {
|
for (uint8 i = 0; i < 15; i++) {
|
||||||
data.push(bytes1(i));
|
data.push(bytes1(i));
|
||||||
}
|
}
|
||||||
assembly {
|
assembly {
|
||||||
r := sload(data_slot)
|
r := sload(data.slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_long() public returns (uint256 r) {
|
function test_long() public returns (uint256 r) {
|
||||||
assembly {
|
assembly {
|
||||||
sstore(data_slot, 0)
|
sstore(data.slot, 0)
|
||||||
}
|
}
|
||||||
for (uint8 i = 0; i < 33; i++) {
|
for (uint8 i = 0; i < 33; i++) {
|
||||||
data.push(bytes1(i));
|
data.push(bytes1(i));
|
||||||
}
|
}
|
||||||
assembly {
|
assembly {
|
||||||
r := sload(data_slot)
|
r := sload(data.slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_pop() public returns (uint256 r) {
|
function test_pop() public returns (uint256 r) {
|
||||||
assembly {
|
assembly {
|
||||||
sstore(data_slot, 0)
|
sstore(data.slot, 0)
|
||||||
}
|
}
|
||||||
for (uint8 i = 0; i < 32; i++) {
|
for (uint8 i = 0; i < 32; i++) {
|
||||||
data.push(bytes1(i));
|
data.push(bytes1(i));
|
||||||
}
|
}
|
||||||
data.pop();
|
data.pop();
|
||||||
assembly {
|
assembly {
|
||||||
r := sload(data_slot)
|
r := sload(data.slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ contract C {
|
|||||||
data.push(123);
|
data.push(123);
|
||||||
delete data;
|
delete data;
|
||||||
assembly {
|
assembly {
|
||||||
ret := sload(data_slot)
|
ret := sload(data.slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
x = m;
|
x = m;
|
||||||
assembly {
|
assembly {
|
||||||
r := sload(x_slot)
|
r := sload(x.slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ contract C {
|
|||||||
uint256 off1;
|
uint256 off1;
|
||||||
uint256 off2;
|
uint256 off2;
|
||||||
assembly {
|
assembly {
|
||||||
sstore(z_slot, 7)
|
sstore(z.slot, 7)
|
||||||
off1 := z_offset
|
off1 := z.offset
|
||||||
off2 := y_offset
|
off2 := y.offset
|
||||||
}
|
}
|
||||||
assert(off1 == 0);
|
assert(off1 == 0);
|
||||||
assert(off2 == 2);
|
assert(off2 == 2);
|
||||||
|
@ -8,8 +8,8 @@ contract C {
|
|||||||
uint256 off2;
|
uint256 off2;
|
||||||
assembly {
|
assembly {
|
||||||
function f() -> o1 {
|
function f() -> o1 {
|
||||||
sstore(z_slot, 7)
|
sstore(z.slot, 7)
|
||||||
o1 := y_offset
|
o1 := y.offset
|
||||||
}
|
}
|
||||||
off2 := f()
|
off2 := f()
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ contract C {
|
|||||||
Data storage x = a;
|
Data storage x = a;
|
||||||
uint256 off;
|
uint256 off;
|
||||||
assembly {
|
assembly {
|
||||||
sstore(x_slot, 7)
|
sstore(x.slot, 7)
|
||||||
off := x_offset
|
off := x.offset
|
||||||
}
|
}
|
||||||
assert(off == 0);
|
assert(off == 0);
|
||||||
return true;
|
return true;
|
||||||
|
@ -13,7 +13,7 @@ contract C {
|
|||||||
|
|
||||||
bytes32 slot = keccak256(abi.encode(uint(1), uint(0)));
|
bytes32 slot = keccak256(abi.encode(uint(1), uint(0)));
|
||||||
assembly {
|
assembly {
|
||||||
_data_slot := slot
|
_data.slot := slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ contract C {
|
|||||||
}
|
}
|
||||||
function g() public returns (bool, uint256) {
|
function g() public returns (bool, uint256) {
|
||||||
uint256 ys;
|
uint256 ys;
|
||||||
assembly { ys := y_slot }
|
assembly { ys := y.slot }
|
||||||
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
return (success, success ? abi.decode(data,(uint256)) : 0);
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
}
|
}
|
||||||
function h() public returns (bool, uint256) {
|
function h() public returns (bool, uint256) {
|
||||||
uint256 ys;
|
uint256 ys;
|
||||||
assembly { ys := y_slot }
|
assembly { ys := y.slot }
|
||||||
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
return (success, success ? abi.decode(data,(uint256)) : 0);
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,13 @@ contract C {
|
|||||||
}
|
}
|
||||||
function g() public returns (bool, uint256) {
|
function g() public returns (bool, uint256) {
|
||||||
uint256 ys;
|
uint256 ys;
|
||||||
assembly { ys := y_slot }
|
assembly { ys := y.slot }
|
||||||
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
return (success, success ? abi.decode(data,(uint256)) : 0);
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
}
|
}
|
||||||
function h() public returns (bool, uint256) {
|
function h() public returns (bool, uint256) {
|
||||||
uint256 ys;
|
uint256 ys;
|
||||||
assembly { ys := y_slot }
|
assembly { ys := y.slot }
|
||||||
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
return (success, success ? abi.decode(data,(uint256)) : 0);
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,13 @@ contract C {
|
|||||||
}
|
}
|
||||||
function g() public returns (bool, uint256) {
|
function g() public returns (bool, uint256) {
|
||||||
uint256 ys;
|
uint256 ys;
|
||||||
assembly { ys := y_slot }
|
assembly { ys := y.slot }
|
||||||
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
return (success, success ? abi.decode(data,(uint256)) : 0);
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
}
|
}
|
||||||
function h() public returns (bool, uint256) {
|
function h() public returns (bool, uint256) {
|
||||||
uint256 ys;
|
uint256 ys;
|
||||||
assembly { ys := y_slot }
|
assembly { ys := y.slot }
|
||||||
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
(bool success, bytes memory data) = address(L).call(abi.encodeWithSelector(L.f.selector, ys));
|
||||||
return (success, success ? abi.decode(data,(uint256)) : 0);
|
return (success, success ? abi.decode(data,(uint256)) : 0);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
function g() public returns (bool, bool, uint256) {
|
function g() public returns (bool, bool, uint256) {
|
||||||
uint256 s_ptr;
|
uint256 s_ptr;
|
||||||
assembly { s_ptr := s_slot }
|
assembly { s_ptr := s.slot }
|
||||||
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.g.selector, s_ptr));
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.g.selector, s_ptr));
|
||||||
return (L.g.selector == bytes4(keccak256("g(uint256[] storage)")), success, abi.decode(data, (uint256)));
|
return (L.g.selector == bytes4(keccak256("g(uint256[] storage)")), success, abi.decode(data, (uint256)));
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ contract C {
|
|||||||
|
|
||||||
function f() public returns (bool, bool, uint256) {
|
function f() public returns (bool, bool, uint256) {
|
||||||
uint256 s_ptr;
|
uint256 s_ptr;
|
||||||
assembly { s_ptr := s_slot }
|
assembly { s_ptr := s.slot }
|
||||||
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, s_ptr));
|
(bool success, bytes memory data) = address(L).delegatecall(abi.encodeWithSelector(L.f.selector, s_ptr));
|
||||||
return (L.f.selector == bytes4(keccak256("f(L.S storage)")), success, abi.decode(data, (uint256)));
|
return (L.f.selector == bytes4(keccak256("f(L.S storage)")), success, abi.decode(data, (uint256)));
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ contract C {
|
|||||||
for (uint i = 3; i < len; i++)
|
for (uint i = 3; i < len; i++)
|
||||||
{
|
{
|
||||||
assembly {
|
assembly {
|
||||||
mstore(0, storageArray_slot)
|
mstore(0, storageArray.slot)
|
||||||
let pos := add(keccak256(0, 0x20), i)
|
let pos := add(keccak256(0, 0x20), i)
|
||||||
|
|
||||||
if iszero(eq(sload(pos), 0)) {
|
if iszero(eq(sload(pos), 0)) {
|
||||||
|
@ -2,7 +2,7 @@ contract C {
|
|||||||
bytes b;
|
bytes b;
|
||||||
function f() public returns (bool correct) {
|
function f() public returns (bool correct) {
|
||||||
assembly {
|
assembly {
|
||||||
sstore(b_slot, or("deadbeef", 0x08))
|
sstore(b.slot, or("deadbeef", 0x08))
|
||||||
}
|
}
|
||||||
byte s = b[3];
|
byte s = b[3];
|
||||||
uint r;
|
uint r;
|
||||||
|
@ -2,8 +2,8 @@ contract C {
|
|||||||
bytes b;
|
bytes b;
|
||||||
function f() public returns (bool correct) {
|
function f() public returns (bool correct) {
|
||||||
assembly {
|
assembly {
|
||||||
sstore(b_slot, 0x41)
|
sstore(b.slot, 0x41)
|
||||||
mstore(0, b_slot)
|
mstore(0, b.slot)
|
||||||
sstore(keccak256(0, 0x20), "deadbeefdeadbeefdeadbeefdeadbeef")
|
sstore(keccak256(0, 0x20), "deadbeefdeadbeefdeadbeefdeadbeef")
|
||||||
}
|
}
|
||||||
byte s = b[31];
|
byte s = b[31];
|
||||||
|
@ -3,7 +3,7 @@ contract C {
|
|||||||
function f() public returns (bool correct) {
|
function f() public returns (bool correct) {
|
||||||
s.push();
|
s.push();
|
||||||
assembly {
|
assembly {
|
||||||
mstore(0, s_slot)
|
mstore(0, s.slot)
|
||||||
sstore(keccak256(0, 0x20), 257)
|
sstore(keccak256(0, 0x20), 257)
|
||||||
}
|
}
|
||||||
uint8 x = s[0];
|
uint8 x = s[0];
|
||||||
|
@ -2,7 +2,7 @@ contract C {
|
|||||||
uint8[1] s;
|
uint8[1] s;
|
||||||
function f() public returns (bool correct) {
|
function f() public returns (bool correct) {
|
||||||
assembly {
|
assembly {
|
||||||
sstore(s_slot, 257)
|
sstore(s.slot, 257)
|
||||||
}
|
}
|
||||||
uint8 x = s[0];
|
uint8 x = s[0];
|
||||||
uint r;
|
uint r;
|
||||||
|
@ -6,7 +6,7 @@ contract C {
|
|||||||
function f() public returns (bool correct) {
|
function f() public returns (bool correct) {
|
||||||
s.m.push();
|
s.m.push();
|
||||||
assembly {
|
assembly {
|
||||||
mstore(0, s_slot)
|
mstore(0, s.slot)
|
||||||
sstore(keccak256(0, 0x20), 257)
|
sstore(keccak256(0, 0x20), 257)
|
||||||
}
|
}
|
||||||
uint8 x = s.m[0];
|
uint8 x = s.m[0];
|
||||||
|
@ -4,28 +4,28 @@ contract C {
|
|||||||
function f() internal pure {
|
function f() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,0) { c_slot := s_slot } {}
|
for {} eq(0,0) { c.slot := s.slot } {}
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
function g() internal pure {
|
function g() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,1) { c_slot := s_slot } {}
|
for {} eq(0,1) { c.slot := s.slot } {}
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
function h() internal pure {
|
function h() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,0) {} { c_slot := s_slot }
|
for {} eq(0,0) {} { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
function i() internal pure {
|
function i() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,1) {} { c_slot := s_slot }
|
for {} eq(0,1) {} { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@ contract C {
|
|||||||
function f() internal pure {
|
function f() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
for { c_slot := s_slot } iszero(0) {} {}
|
for { c.slot := s.slot } iszero(0) {} {}
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
function g() internal pure {
|
function g() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
for { c_slot := s_slot } iszero(1) {} {}
|
for { c.slot := s.slot } iszero(1) {} {}
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ contract C {
|
|||||||
function f(bool flag) internal pure {
|
function f(bool flag) internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
if flag { c_slot := s_slot }
|
if flag { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ contract C {
|
|||||||
assembly {
|
assembly {
|
||||||
function f() { return(0, 0) }
|
function f() { return(0, 0) }
|
||||||
f()
|
f()
|
||||||
c_slot := s_slot
|
c.slot := s.slot
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ contract C {
|
|||||||
function f() internal pure {
|
function f() internal pure {
|
||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
c_slot := s_slot
|
c.slot := s.slot
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ contract C {
|
|||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
@ -13,8 +13,8 @@ contract C {
|
|||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
switch flag
|
switch flag
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
case 1 { c_slot := s_slot }
|
case 1 { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ contract C {
|
|||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
default { return(0,0) }
|
default { return(0,0) }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
|
@ -5,8 +5,8 @@ contract C {
|
|||||||
S storage c;
|
S storage c;
|
||||||
assembly {
|
assembly {
|
||||||
switch flag
|
switch flag
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
default { c_slot := s_slot }
|
default { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@ contract C {
|
|||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
case 0 { revert(0, 0) }
|
case 0 { revert(0, 0) }
|
||||||
default { c_slot := s_slot }
|
default { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
c;
|
c;
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,22 @@ contract C {
|
|||||||
S s;
|
S s;
|
||||||
function f() internal pure returns (S storage c) {
|
function f() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,0) { c_slot := s_slot } {}
|
for {} eq(0,0) { c.slot := s.slot } {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function g() internal pure returns (S storage c) {
|
function g() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,1) { c_slot := s_slot } {}
|
for {} eq(0,1) { c.slot := s.slot } {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function h() internal pure returns (S storage c) {
|
function h() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,0) {} { c_slot := s_slot }
|
for {} eq(0,0) {} { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function i() internal pure returns (S storage c) {
|
function i() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
for {} eq(0,1) {} { c_slot := s_slot }
|
for {} eq(0,1) {} { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@ contract C {
|
|||||||
S s;
|
S s;
|
||||||
function f() internal pure returns (S storage c) {
|
function f() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
for { c_slot := s_slot } iszero(0) {} {}
|
for { c.slot := s.slot } iszero(0) {} {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function g() internal pure returns (S storage c) {
|
function g() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
for { c_slot := s_slot } iszero(1) {} {}
|
for { c.slot := s.slot } iszero(1) {} {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ contract C {
|
|||||||
S s;
|
S s;
|
||||||
function f(bool flag) internal pure returns (S storage c) {
|
function f(bool flag) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
if flag { c_slot := s_slot }
|
if flag { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ contract C {
|
|||||||
assembly {
|
assembly {
|
||||||
function f() { return(0, 0) }
|
function f() { return(0, 0) }
|
||||||
f()
|
f()
|
||||||
c_slot := s_slot
|
c.slot := s.slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ contract C {
|
|||||||
S s;
|
S s;
|
||||||
function f() internal pure returns (S storage c) {
|
function f() internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
c_slot := s_slot
|
c.slot := s.slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,20 @@ contract C {
|
|||||||
function f(uint256 a) internal pure returns (S storage c) {
|
function f(uint256 a) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function g(bool flag) internal pure returns (S storage c) {
|
function g(bool flag) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
switch flag
|
switch flag
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
case 1 { c_slot := s_slot }
|
case 1 { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function h(uint256 a) internal pure returns (S storage c) {
|
function h(uint256 a) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
default { return(0,0) }
|
default { return(0,0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,15 @@ contract C {
|
|||||||
function f(bool flag) internal pure returns (S storage c) {
|
function f(bool flag) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
switch flag
|
switch flag
|
||||||
case 0 { c_slot := s_slot }
|
case 0 { c.slot := s.slot }
|
||||||
default { c_slot := s_slot }
|
default { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function g(uint256 a) internal pure returns (S storage c) {
|
function g(uint256 a) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
case 0 { revert(0, 0) }
|
case 0 { revert(0, 0) }
|
||||||
default { c_slot := s_slot }
|
default { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ contract C {
|
|||||||
function f(uint256 a) internal pure returns (S storage c) {
|
function f(uint256 a) internal pure returns (S storage c) {
|
||||||
assembly {
|
assembly {
|
||||||
switch a
|
switch a
|
||||||
default { c_slot := s_slot }
|
default { c.slot := s.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
contract C {
|
contract C {
|
||||||
uint[] r;
|
uint[] r;
|
||||||
function f() internal view returns (uint[] storage s) {
|
function f() internal view returns (uint[] storage s) {
|
||||||
assembly { pop(s_slot) }
|
assembly { pop(s.slot) }
|
||||||
s = r;
|
s = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ contract test {
|
|||||||
uint constant x = 2;
|
uint constant x = 2;
|
||||||
function f() pure public {
|
function f() pure public {
|
||||||
assembly {
|
assembly {
|
||||||
let r := x_offset
|
let r := x.offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 6617: (112-120): The suffixes _offset and _slot can only be used on non-constant storage variables.
|
// TypeError 6617: (112-120): The suffixes .offset and .slot can only be used on non-constant storage variables.
|
||||||
|
@ -3,7 +3,7 @@ contract test {
|
|||||||
function f() public {
|
function f() public {
|
||||||
uint[] storage a = r;
|
uint[] storage a = r;
|
||||||
assembly {
|
assembly {
|
||||||
function g() -> x { x := a_offset }
|
function g() -> x { x := a.offset }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,4 +7,4 @@ contract test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1408: (89-90): Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.
|
// TypeError 1408: (89-90): Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.
|
||||||
|
@ -10,4 +10,4 @@ contract test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1408: (80-81): Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.
|
// TypeError 1408: (80-81): Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.
|
||||||
|
@ -2,7 +2,7 @@ contract test {
|
|||||||
uint a;
|
uint a;
|
||||||
function f() pure public {
|
function f() pure public {
|
||||||
assembly {
|
assembly {
|
||||||
function g() -> x { x := a_slot }
|
function g() -> x { x := a.slot }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,4 @@ contract c {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1408: (75-76): Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.
|
// TypeError 1408: (75-76): Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
assembly {
|
assembly {
|
||||||
let x_offset := 1
|
let x.offset := 1
|
||||||
let x_slot := 1
|
let x.slot := 1
|
||||||
let _offset := 1
|
|
||||||
let _slot := 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// DeclarationError 9155: (79-87): In variable declarations _slot and _offset can not be used as a suffix.
|
// DeclarationError 3927: (79-87): User-defined identifiers in inline assembly cannot contain '.'.
|
||||||
// DeclarationError 9155: (109-115): In variable declarations _slot and _offset can not be used as a suffix.
|
// DeclarationError 3927: (109-115): User-defined identifiers in inline assembly cannot contain '.'.
|
||||||
// DeclarationError 9155: (137-144): In variable declarations _slot and _offset can not be used as a suffix.
|
|
||||||
// DeclarationError 9155: (166-171): In variable declarations _slot and _offset can not be used as a suffix.
|
|
||||||
|
@ -16,4 +16,3 @@ contract B {
|
|||||||
// ----
|
// ----
|
||||||
// DeclarationError 3859: (b:105-106): This declaration shadows a declaration outside the inline assembly block.
|
// DeclarationError 3859: (b:105-106): This declaration shadows a declaration outside the inline assembly block.
|
||||||
// DeclarationError 3927: (b:128-131): User-defined identifiers in inline assembly cannot contain '.'.
|
// DeclarationError 3927: (b:128-131): User-defined identifiers in inline assembly cannot contain '.'.
|
||||||
// DeclarationError 3859: (b:128-131): The prefix of this declaration conflicts with a declaration outside the inline assembly block.
|
|
||||||
|
@ -11,6 +11,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// DeclarationError 3927: (115-118): User-defined identifiers in inline assembly cannot contain '.'.
|
// DeclarationError 3927: (115-118): User-defined identifiers in inline assembly cannot contain '.'.
|
||||||
// DeclarationError 3859: (115-118): The prefix of this declaration conflicts with a declaration outside the inline assembly block.
|
|
||||||
// DeclarationError 3927: (140-143): User-defined identifiers in inline assembly cannot contain '.'.
|
// DeclarationError 3927: (140-143): User-defined identifiers in inline assembly cannot contain '.'.
|
||||||
// DeclarationError 3859: (140-143): The prefix of this declaration conflicts with a declaration outside the inline assembly block.
|
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 9068: (118-119): You have to use the _slot or _offset suffix to access storage reference variables.
|
// TypeError 9068: (118-119): You have to use the .slot or .offset suffix to access storage reference variables.
|
||||||
|
@ -3,10 +3,10 @@ contract C {
|
|||||||
fallback() external {
|
fallback() external {
|
||||||
uint[] storage y = x;
|
uint[] storage y = x;
|
||||||
assembly {
|
assembly {
|
||||||
y_slot := 1
|
y.slot := 1
|
||||||
y_offset := 2
|
y.offset := 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 9739: (138-146): Only _slot can be assigned to.
|
// TypeError 9739: (138-146): Only .slot can be assigned to.
|
||||||
|
@ -2,8 +2,8 @@ contract C {
|
|||||||
uint[] x;
|
uint[] x;
|
||||||
fallback() external {
|
fallback() external {
|
||||||
assembly {
|
assembly {
|
||||||
x_slot := 1
|
x.slot := 1
|
||||||
x_offset := 2
|
x.offset := 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
assembly {
|
assembly {
|
||||||
let x := _offset
|
let x := .offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// DeclarationError 4794: (84-91): In variable names _slot and _offset can only be used as a suffix.
|
// ParserError 1856: (84-85): Literal or identifier expected.
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
assembly {
|
assembly {
|
||||||
let x := _slot
|
let x := .slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// DeclarationError 4794: (84-89): In variable names _slot and _offset can only be used as a suffix.
|
// ParserError 1856: (84-85): Literal or identifier expected.
|
||||||
|
@ -3,8 +3,8 @@ contract C {
|
|||||||
fallback() external {
|
fallback() external {
|
||||||
uint[] storage y = x;
|
uint[] storage y = x;
|
||||||
assembly {
|
assembly {
|
||||||
pop(y_slot)
|
pop(y.slot)
|
||||||
pop(y_offset)
|
pop(y.offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
contract C {
|
||||||
|
uint[] x;
|
||||||
|
fallback() external {
|
||||||
|
uint[] storage y = x;
|
||||||
|
assembly {
|
||||||
|
pop(y_slot)
|
||||||
|
pop(y_offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// DeclarationError 9467: (118-124): Identifier not found. Use ``.slot`` and ``.offset`` to access storage variables.
|
||||||
|
// DeclarationError 9467: (142-150): Identifier not found. Use ``.slot`` and ``.offset`` to access storage variables.
|
@ -0,0 +1,14 @@
|
|||||||
|
contract C {
|
||||||
|
uint[] x;
|
||||||
|
fallback() external {
|
||||||
|
uint y_slot = 2;
|
||||||
|
uint y_offset = 3;
|
||||||
|
uint[] storage y = x;
|
||||||
|
assembly {
|
||||||
|
pop(y_slot)
|
||||||
|
pop(y_offset)
|
||||||
|
}
|
||||||
|
y[0] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
@ -1,9 +1,9 @@
|
|||||||
contract C {
|
contract C {
|
||||||
function f() pure public {
|
function f() pure public {
|
||||||
assembly {
|
assembly {
|
||||||
let x := f_slot
|
let x := f.slot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 7944: (84-90): The suffixes _offset and _slot can only be used on storage variables.
|
// TypeError 7944: (84-90): The suffixes .offset and .slot can only be used on storage variables.
|
||||||
|
@ -3,11 +3,11 @@ contract C {
|
|||||||
fallback() external {
|
fallback() external {
|
||||||
uint[] memory y = x;
|
uint[] memory y = x;
|
||||||
assembly {
|
assembly {
|
||||||
pop(y_slot)
|
pop(y.slot)
|
||||||
pop(y_offset)
|
pop(y.offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 3622: (117-123): The suffixes _offset and _slot can only be used on storage variables.
|
// TypeError 3622: (117-123): The suffixes .offset and .slot can only be used on storage variables.
|
||||||
// TypeError 3622: (141-149): The suffixes _offset and _slot can only be used on storage variables.
|
// TypeError 3622: (141-149): The suffixes .offset and .slot can only be used on storage variables.
|
||||||
|
@ -3,10 +3,10 @@ contract C {
|
|||||||
fallback() external {
|
fallback() external {
|
||||||
uint[] storage y = x;
|
uint[] storage y = x;
|
||||||
assembly {
|
assembly {
|
||||||
y_slot := 1
|
y.slot := 1
|
||||||
y_offset := 2
|
y.offset := 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 9739: (138-146): Only _slot can be assigned to.
|
// TypeError 9739: (138-146): Only .slot can be assigned to.
|
||||||
|
@ -2,7 +2,7 @@ contract C {
|
|||||||
struct S { uint x; }
|
struct S { uint x; }
|
||||||
S s;
|
S s;
|
||||||
function e() pure public {
|
function e() pure public {
|
||||||
assembly { mstore(keccak256(0, 20), mul(s_slot, 2)) }
|
assembly { mstore(keccak256(0, 20), mul(s.slot, 2)) }
|
||||||
}
|
}
|
||||||
function f() pure public {
|
function f() pure public {
|
||||||
uint x;
|
uint x;
|
||||||
|
Loading…
Reference in New Issue
Block a user